宏定义

  • #define 是预处理器处理的单元实体之一
  • #define 定义的宏可以出现在程序的任意位置
  • #define 定义之后的代码都可使用这个宏

#开头的表示他是预处理处理的单元实体之一

宏常量

  • #define 定义的宏常量可以直接使用
  • #define 定义的宏常量本质为字面量

字面量意味着他不占用任何的内存

#define 并不会占用内存,它只是在编译前做了一个文本替换,不涉及任何存储或运行时的内存分配。

1
2
3
4
5
#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\ // 类似 D:testtest.c
test.c

对于预处理器而言,这四个宏定义都是正确的,因为他不会进行语法检查;

对于预处理来说虽然正确,但是替换后的代码是不符合 C 语言语法规范的,因此编译器肯定会报错的(PATH2、PATH3)

宏定义表达式

  • #define 表达式的使用类似函数调用
  • #define 表达式可以比函数更强大
  • #define 表达式比函数更容易出错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stcio.h>

#define _SUM_(a, b) (a) + (b)
#define _MIN_(a, b) ((a), (b)? (a) : (b))
#define _DIM_(a) sizeof(a) / sizeof(*a)

int main() {
int a = 1;
iint b = 2;
int c[4] = {0};

int s1 = _SUM_(a, b);
int s2 = _SUM_(a, b) * _SUM_(a, b);
int m = _MIN_(a++, b);
int d = _DIM_(c);

printf("s1 = %d\n", s1); // s1 = 3
printf("s2 = %d\n", s2); // s2 = 5 (a) + (b) * (a) + (b)
printf("m = %d\n", m); // m = 2 ((a++) < (b)? (a++) : (b));
printf("d = %d\n", d); // d = 4

return 0;
}

宏表达式与函数的对比

  • 宏表达式被预处理器处理,编译器不知道宏表达式的存在(编译器阶段已经被预处理器替换掉了)

  • 宏表达式用”实参“完全代替形参,不进行任何运算

  • 宏表达式**没有任何的”调用“开销

  • 宏表达式中不能出现递归定义

    宏没有作用域的概念或者说限制,因为编译器根本不知道宏的存在

内置宏

1
2
3
4
5
_FILE_: 被编译的文件名
_LINE_: 当前行号
_DATE_: 编译时的日期
_TIME_: 编译时的时间
_STDC_: 编译器是否遵循标准 C 规范

条件编译

同一份代码产生不同的产品

  • 条件编译的行为类似于 C 语言中的 if…else…
  • 条件编译是预编译指令命令,用于控制是否编译某段代码
1
2
3
4
5
6
7
8
9
10
#define C 1
int main() {
#if(C == 1)
printf("This is first printf...\n");
#else
printf("This is second printf...\n");
#endif

return 0;
}

#if…#else… 是用来给预编译器执行的

条件编译的本质

  • 预编译器根据条件编译指令有选择的删除代码
  • 编译器不知道代码分支的存在
  • if…else…语句在运行期进行分支判断
  • 条件编译指令在预编译期进行分支判断
  • 可以通过命令行定义宏
1
2
3
gcc -Dmacro=value file.c // -D 表示宏定义,等价于 #define macro value

gcc -Dmacro file.c
1
2
3
4
5
6
7
8
9
int main() {
#ifdef C // 检测后面这个宏是否存在,存在就执行后面的代码 This is first printf...
printf("This is first printf...\n");
#else
printf("This is second printf...\n");
#endif

return 0;
}

#include的本质

  • #include 的本质是将已经存在的文件内容嵌入到当前文件中
  • #include 的间接包含,同样会产生嵌入文件内容的操作

includebenzhi.png

包含同样的 #include 可能会产生重复定义的问题,在编译期会导致报错

使用 #ifdef 可以解决这样的问题