1.预处理
程序在编译之前,是由预处理器CC1先检查c文件有没有以#号开头的符号称为宏
如果有,CC1是不会做任何的逻辑判断直接将里里面的内容替换出来,或者拷贝出来
我们把这种方式称为宏展开
预处理指令(宏)包括
1.头文件 #include
2.定义宏 #define
3.取消 #undef
4.条件编译 #if #ifdef #ifndef #else #elif #endif
5.向编译器发送指令 #pragma
#pragma pack(1) // 设置结构体M值的大小
加载库
2.宏的概念
宏其实就是一段特定的字符串,在预处理的时候会被替换
3.宏的分类
1.无参宏之自定义宏
无参宏的意思是使用的时候无需指定任何的参数
例如:
#define PI 3.14
#define LCD_SIZE 800*480*4
注意:此处的PI表示宏,一般使用大写字母表示,用于区分变量和函数,当然这不是
语法规定,只是个人习惯而已
2.无参宏之系统宏
#define O_RDONLY : 0x1
#define O_WRONLY : 0X2
#define NULL ((void *)0) char *p = NULL 等价于 char *p = (void *)0;
3.带参宏
带参宏意味着宏定义是可以带参数的,从形式上看是和函数很像
#define MAX(a,b) a>b ? a : b
#define MIN(a,b) a<b ? a : b
4.带参数的宏的特点:
1.直接文本替换,不做任何的语法判断,不做任何的中间转换
2.宏在预编译的时候已经被替换了,所以运行的时候不存在宏
3.宏展开的时候浪费了内存空间,但是节约了程序运行的时间
5.带参宏的问题解决方式:
//#define MAX(a,b) a>b ? a : b // 容易出bug 解决方法如下
#define MAX(a,b) ((a)>(b) ? (a) : (b))
6.无值的宏
#define _MYHEAD_H
#define WIN_32
#define WIN_64
无值宏一般是头文件或者在编译中作为判断条件出现
7.总结
1.宏是用于替换指定的表达式,增加代码的可读性
2.使得程序修改比较方便,如果程序有多个地方使用到宏的时候,只需要修改宏定义即可
3.提高程序的运行效率
2.条件编译
是用来控制编译器编译哪一段代码
#if 如果条件为真,则执行相应的操作,可以起到类似于注释的效果
#elif 如果前面的为假,那么执行此语句
#else 如果前面的操作都为假,则执行以下语句
#endif 结束条件编译
#ifdef 如果改宏已经被定义则执行相应的操作
#ifndef 如果宏没被定义,则执行相应的操作
#if -- #else -- #endif
格式如下:
#if 条件表达式
代码段1
#else
代码段2
#endif
demo:
#define DEBUG 1
int main()
{
#if 0 // 0 为假
printf("此处为假\n");
#else
printf("此处为真\n");
#endif
#if DEBUG //DEBUG 为真
printf("此处为真\n");
#else
printf("此处为假\n");
#endif // 结束
return 0;
}
条件编译,多路分支
#if -- #elif -- #elif -- #endif
#define A 1
#define B 2
#define C 3
//-----------------
#if A
printf("A\n");
#elif B
printf("A\n");
#elif C
printf("A\n");
#endif
检测程序中如果没有定义宏则定义
#ifndef --- #define --- #endif
定义格式
#ifndef 标识符
#define 标识符 替换列表
#endif
demo:
#define PI 3.1415
#ifndef PI
#define PI 3.14
#endif
运用场景主要是头文件
检测如果定义了宏则删除
#ifdef -- #undef -- #endif
定义格式:
#ifdef 标识符
代码段1
#endif
demo:
#define N 456
#ifdef N
#undef N
#define N 123
#endif
条件编译的使用场景
在程序中,用条件编译将调试语句包裹起来,通过gcc编译器来选择编译哪一段
代码
int main()
{
#ifdef A // 现在没有定义此宏
printf("A\n");
#else
printf("haha\n");
#endif
}
编译方法:
gcc main.c -o main -DA // -D 的意思是编译程序的时候定义哪一个宏
作业:
现有一个嵌入式设备终端传输过来的数据包是一个32位无符号的整型数,这个数据包里面各位含义如下:
00-07位:表示温度数据
08-15位:表示湿度数据
16-19位:表示4扇门状态(门的编号0-3) 二进制:0001 0010 0100 1000 十六进制 1 2 4 8
20-23位:表示四盏灯的状态(灯编号0-3)
24-31位:预留备用
下面是最近一段时间接受的数据包:
0x12344520, 0xff004B1C,0x00553C1E
请编写一个程序接收这3个数据包,并解析出对应的数据【温度,湿度,门0-3,灯0-3】(门和灯的状态0-关,1-开)。
使用宏来实现以上功能:
提示
#define TEMP_MASK 0x000000FF
#define HUMI_MASK 0x0000FF00
#include <stdio.h>
#define TEMP_MASK 0x000000FF
#define HUMI_MASK 0x0000FF00
#define TEMPERATURE(a) ((a&TEMP_MASK) >> 0)
#define HUMIDITY(a) ((a&HUMI_MASK) >> 8)
#define DOOR0_MASK 0x00010000
#define DOOR1_MASK 0x00020000
#define DOOR2_MASK 0x00040000
#define DOOR3_MASK 0x00080000
#define LIGHT0_MASK 0x00100000
#define LIGHT1_MASK 0x00200000
#define LIGHT2_MASK 0x00400000
#define LIGHT3_MASK 0x00800000
int main()
{
unsigned int data;
printf("请输入接收到的数据:\n");
while(1)
{
scanf("%x",data);
printf("温度: %d\n",TEMPERATURE(data));
printf("湿度: %d\n",TEMPERATURE(HUMIDITY));
printf("门0: %s\t",(data & DOOR0_MASK) ? "开":"关");
printf("门1: %s\t",(data & DOOR1_MASK) ? "开":"关");
printf("门2: %s\t",(data & DOOR2_MASK) ? "开":"关");
printf("门3: %s\t",(data & DOOR3_MASK) ? "开":"关");
printf("灯0: %s\t",(data & LIGHT0_MASK) ? "亮":"灭");
printf("灯1: %s\t",(data & LIGHT1_MASK) ? "亮":"灭");
printf("灯2: %s\t",(data & LIGHT2_MASK) ? "亮":"灭");
printf("灯3: %s\t",(data & LIGHT3_MASK) ? "亮":"灭");
}
}