***when to do? how to do? why to do?***
2-1 GCC的使用及其常用选项介绍
1 GCC(GNU C Compiler)
翻译官 翻译组织。
随着GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection。GCC按照后缀名的不同,调用翻译组织中不同的翻译官。
gcc -o output
gcc -o 输出的文件名 输入文件名,实例如下所示。
gcc -v -o
扩充:
在Linux系统中,返回值0代表成功,非0代表不成功。
2 C语言编译过程
C语言编译过程:预处理,编译,汇编,链接。
预处理:替换。【gcc -E】
编译:【gcc -S】
汇编:【gcc -c】
链接:链接系统标准库。【gcc -o】
Q1:define include是关键字吗?
A1:define include 是在预处理阶段处理的,不是在编译阶段处理的,所以不是关键字。
3 C语言常见错误举例
1,预处理错误:
#include "name":" ",双引号是自定义的头文件(当前目录下)。
#include <name>:< >,尖括号是系统库的头文件。
not find错误:gcc -I 跟查找头文件的目录。
编译错误:语法错误,;,{ }
链接错误:
原材料不够(undefined references to "fun"):寻找标签是否实现了,链接时是否加入一起链接。
或多了(multiple definition of "fun"):多次实现了标签,只保留一个标签的实现。
4 预处理的使用
#include 包含头文件
#define 宏 替换,不进行语法检查
#define 宏名 宏体 加括号
#ifdef #else #endif 条件编译
预定义宏
_FUNCTION_:函数名
_LINE_:行号
_FILE_:文件名
扩充:gcc -D:gcc -DABC === #define ABC
宏展开下的#、##:
#:字符串化
##:连接符号
#define ABC(x) #x
#define ABC(x) day##x
2-2 C语言常用关键字及运算符操作
1 关键字
编译器预先定义了一定意义的字符串。32个关键字。
01 杂项
sizeof:编译器给我们查看内存空间的一个工具。任何环境都可以实现。
int a;
printf("the a is %d\n",sizeof(a));
return:返回的概念。
02 数据类型
C操作对象:资源/内存{内存类型的资源,LCD缓存、LED灯}
C语言如何描述这些资源的属性?
资源属性【大小】;限制内存的大小,关键字。
数据类型:
char:
硬件芯片的最小单位:bit 1 0
软件操作的最小单位(1B == 8bit):char a;
应用场景:硬件处理的最小单位。
int:
大小:根据编译器来决定,32bit为4B。
编译器最优的处理大小:系统一个周期,所能接收的最大的处理单位,int。
整型常量:
long、short:特殊长度的限制符。
unsigned、signed:数据类型的限制标志,有无符号。默认为有符号数。
无符号:数据
有符号:数字
内存空间的最高字节,是符号位 还是数据
float、double:
大小:float 4B double 8B
内存存在形式:
void:声明标志,语义符。
03 自定义数据类型
C编译器默认定义的内存分配不符合实际资源的形式。自定义 = 基本元素的集合。
struct:结构体,元素之间的和。递增累加顺序。
struct myabc{
unsigned int a;
unsigned int b;
unsigned int c;
unsigned int d;
};
struct myabc mybuf;
----------------------------
顺序有要求。
union:共用体,共用起始地址的一段内存。应用于技巧型代码。
union myabc{
char a;
int b;
};
union myabc abc;
enum:enumerate---列举,被命名的整形常数集合。
enum 枚举类型{常量列表};
enum week{
Monday = 0, Tuesday = 1, Wednesday = 2,
Thursday,Friday,Saturday,Sunday
};
typedef:数据类型的别名。
xxx_t:typedef
int a; a是一个int类型的变量
typedef int a_t;a是一个int类型的外号
a_t mysize;
04 逻辑结构
CPU顺序执行程序。分支和循环
if、else:
switch、case、default:多分支
switch(整形数字)
do、while、for:循环
for:次数
while:条件
continue、break、goto:
goto:函数内部跳转使用较安全
05 类型修饰符
对内存资源存放位置的限定,资源属性中位置的限定
auto:默认情况,分配的内存可读可写的区域。
区域如果在{ },栈空间
register:定义一些快速访问的变量。编译器会尽量的安排CPU的寄存器去存放这个A,如果寄存器不足时,A还是放在存储器中。&这个符号对register不起作用
auto int a:
register int a:限制变量定义在寄存器的修饰符
----------------------------------------
内存(存储器) 寄存器
0x100 R0,R2
static:静态
应用场景:修饰3种数据。
1)函数内部的变量
2)函数外部的变量,即全局变量
3)函数的修饰符
const:常量的定义,只读的变量
extern:外部声明
volatile:告知编译器编译方法的关键字,不优化编译。修饰变量值的修改,不仅仅可以通过软件,也可以通过其他方式(硬件外部的用户)。
2 运算符
01 算术操作运算
+、-、*、/、%
02 逻辑运算
真 假,二值性,返回的结果是0或1。
||、&&、>、 >=、 <、 <=、 !、 ? :
03 位运算
<<、 >>、 &、 |、 ^、~
左移,乘法,符号变量无关;
右移,除法,符号变量有关。右移时,负数最高位填1,正数最高位填0。
&:取出,清零器;
a = (a | (0x1<<5)); SET
|:保留,设置为高电平的方法
a = (a & ~(0x1<<5)); RESET
^:数据交换
int a = 20,b = 30;
***a = a ^ b; b = a ^ b; a = a ^ b;***
a = 30, b = 20
04 赋值运算
=、+=、-=、&=、...
05 内存访问符号
( )、[ ]、{ }、->、.、&、*
3 逻辑操作
顺序执行, 分支执行, 循环执行
2-3 C语言内存空间的使用
1 指针
01 指针概述
指针概述:内存类型资源地址、门牌号的代名词
指针:
指针变量:存放指针这个概念的盒子
C语言编译器对指针这个特殊的概念,有两个疑问?
1,分配一个盒子,盒子要多大?
在32位系统中,指针就4个字节
2,盒子里存放的地址,所指向的内存读取方法是什么?
char *p;int *p;
注:指针指向内存空间,一定要保证合法性。
02 指针+修饰符
const:常量,只读【不可变】
内存属性:1,内存操作的大小。2,内存的变化性,可读可写。
const char *p :字符串 “helloworld" 内容不可更改
char * const p :硬件资源 LCD 内容可以更改
const char * const p:ROM
volatile:防止优化指向内存地址。只和硬件有关。
char *p;
volatile char *p;
*p == 0x10;
typedef:
char *name_t:name_t是一个指针,指向了一个char类型的内存;
typedef char *name_t:name_t是一个指针类型的名称,指向了一个char类型的内存。
name_t abc;
03 指针+运算符
++、--、+、-:
int *p = xxx [0x12]
p + n [0x12 + n * (sizeof(*p))]
指针的加法运算,实际上加的是一个单位,单位的大小可以使用sizeof(p[0])
p++ p--,更新地址
[ ]:地址变量
变量名[n],n:ID 标签。地址内容的标签访问方式,取出标签里的内存值
逻辑操作符:>= <= == !=
1,跟一个特殊值进行比较 0x0:地址的无效值,结束标志
2,指针必须是同类型的比较才有意义
04 多级指针
int **p;
存放地址的地址空间
p[m] == NULL --->结束了
2 数组
内存分配的一种形式。
01 数组的定义
定义一个空间:
1,大小
2,读取方式
数据类型 数组名[m] m的作用域,只在申请的时候起作用
数组名是一个常量符号,一定不要放到=的左边
如char buf[10] = "abc";
buf = "hello world"; ×
int a[100];
注意:指针是变量,数组的地址的标签,常量
02 数组空间的初始化
空间的赋值
按照标签逐一处理
----》空间定义时,就告知编译器的初始化情况,空间的第一次赋值,初始化操作
第二次内存初始化,赋值? 逐一处理
int a[10] = 空间
C语言本身,CPU内部本身一般不支持空间和空间的拷贝
-------------------------------------------------
数组空间的初始化和变量的初始化本质不同,尤其是嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助。
举例:
char buf[10] = "abc";
buf[2] = 'e'; √ buf指向变量,可以对其进行修改
char *p = "abc";
p[2] = 'e'; × p指向常量,不可以对变量进行修改
字符串的重要属性,结尾一定有个'\0'。
strcpy,strncpy:
一块空间,当成字符空间,提供了一套字符拷贝函数
字符拷贝函数的原则:
内存空间和内存空间的逐一赋值功能的一个封装体
一旦空间中出现了0这个特殊值,函数就即将结束。
strcpy():char buf[10] = ”abc";strcpy(buf,"hello world");
非字符空间:
字符空间:ASCII码编码来解码的空间,---》给人看
非字符空间:数据采集 0x00 - 0xff
拷贝三要素:src,dest,个数
memcpy:
int buf[10];
int sensor_buf[100];
memcpy(buf,sensor_buf,10*sizeof(int));
03 指针与数组
指针数组:
int a[100];
char * a[100]; sizeof(a) = 100 * 4; 存放地址的数组
注:char **a;可以理解为指针数组。
3 结构体、共用体
01 字节对齐
效率,牺牲一点空间换取时间效率
最终结构体的大小,一定是4的倍数
结构体里成员变量顺序不一致,也会影响它的大小
注:32位系统,按照4个字节对齐,实际根据系统默认设置值
4 内存分布图
内存的属性:
1,大小
2,在哪里
编译--》汇编--》链接
01 堆空间
运行时,可以自由,自我管理的分配和释放的空间,生存周期是由程序员来决定。
分配:
malloc(),一旦成功,返回分配好的地址给我们,只需要接收,对于这个新地址的读法,由程序员灵活把握,输入参数指定分配的大小,单位就是B。
char *p
p = (char *)malloc(100);
if(p == NULL){
error
}
释放:
free(p);
02 栈空间
运行时,函数内部使用的变量,函数一旦返回就释放,生存周期是函数内。
03 只读空间
静态空间,整个程序结束时释放内存,生存周期最长。
5 段错误分析
2-4 C语言函数的使用
1 函数概述
一堆代码的集合,用一个标签去描述它。 复用化
函数 数组,函数具备3要素:
1,函数名 (地址)
2,输入参数
3,返回值
在定义函数时,必须将3要素告知编译器。
int fun(int,int,char)
{xxx}
如何用指针保存函数?
char *p;
char(*p) [10];
int (*p) (int,int,char);
2 输入参数
承上启下的功能。
调用者:函数名(要传递的数据) //实参
被调者:函数的具体实现
函数的返回值 函数名(接收的数据) //形参
{
xxx
}
实参传递给形参
传递的形式:拷贝
01 值传递
上层调用者 保护自己空间值不被修改的能力
02 地址传递
上层,调用者 让下层 子函数 修改自己空间值的方式
作用:
1,修改
2,空间传递
2.1 子函数看看空间里的情况
2.2 子函数反向修改上层空间的内容
类似结构体这样的空间,函数与函数之间调用关系---》
连续空间的传递
03 连续空间的传递
1,数组
数组名---标签
实参:
int abc[10];
fun(abc)
形参:
void fun(int *p)
2,结构体
结构体变量
优先选择使用右边的指针方式。
3 返回值
提供启下功能的一种表现形式。
2-5 常见面试题目讲解
1 嵌入式工程师必备0x10道题目
01 宏定义
用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECOND_OF_YEAR (365*24*3600)UL
02 数据声明
用变量a给出下面的定义:
1)一个整型数
int a;
2)一个指向整型数的指针
int *a;
3)一个指向指针的指针,它指向的指针是指向一个整型数
int **a;
4)一个有10个整型数的数组
int a[10];
5)一个有10个指针的数组,该指针是指向一个整型数的
int *a[10];
6)一个指向有10个整型数组的指针
int [10] *a; ---> int (*a)[10];
7)一个指向函数的指针,该函数有一个整形参数并返回一个整型数
int fun(int) *a;---> int (*a)(int);
8)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
int (*a[10])(int);
03 修饰符的使用总结
关键字static的作用是什么?
1)修饰局部变量:
默认局部变量在栈空间存在,生存期比较短
局部静态化,局部变量在静态数据段中保存,生存期非常长
2)修饰全局变量:
防止重命名,限制变量名只在本文件内起作用
3)修饰全局函数
防止重命名,限制该函数名只在本文件内起作用
关键字const有什么含义?
C:只读,建议性 不具备强制性 不等于常量
C++:常量
关键字volatil有什么含义?并给出三个不同的例子。
防止C语言编译器的优化。
它修饰的变量,该变量的修改可能通过第三方来修改。
04 位操作
a |= (0x1<<3);
a &= ~(0x1<<3);