C 语言中以 #
开头的就是预处理指令,例如 #include
。web
全部的预处理指令都会在 GCC 编译过程的预处理步骤解析执行,替换为对应的内容。在下一步编译过程当中,看不到任何预处理信息,只须要对独立的程序文件进行操做便可。svg
#include 头文件
#define 宏名 宏体
#define MY_VAR 3+4
,使用的时候若是是这样 int i = MY_VAR * 5
,会在预处理时替换为 int i = 3+4 * 5
,最终获得的 i 是23。而 #define MY_VAR (3+4)
则无次问题#define MY_FUN(x) (3+x)
,使用 int i = MY_FUN(4)*5
获得的 i 是 35。#ifdef #ifndef #else #endif
例如,对于这个 C 文件:函数
#include <stdio.h> int main() { printf("file is:%s, function is:%s, line is:%d, %s, %s", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__); }
执行结果以下:ui
file is:define.c, function is:main, line is:5, Jan 19 2019, 15:10:57
预处理时,会把全部出现宏名的地方自动替换为对应的宏值。spa
#define 宏名 宏值
宏定义的规则:debug
#define PI 3.14 #define PI2 PI * 2
\
换行,例如:#define PRT printf("%f ", PI); \ printf("%f", PI2)
#define DEBUG
;
,不然会被替换致使异常。综合示例:调试
#include <stdio.h> #define PI 3.14 #define PI2 PI*2 #define PRT printf("%f ", PI); \ printf("%f\n", PI2) #define MIN(a, b) ((a) < (b) ? (a) : (b)) int main() { PRT; printf("%d", MIN(2+3*5, 666)); }
能够带一个或多个参数。有参数的宏的原则是:code
一切地方都有加括号,放在由于运算的优先级致使异常xml
#include <stdio.h> #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define FUN1(a) (a * 5) #define FUN2(a) (a) * 5 int main() { printf("%d\n", MIN(2+3*5, 666)); printf("%d\n", FUN1(5 + 6)); //5 + 6 * 5 = 35 printf("%d\n", 100 / FUN2(5)); //100 / 5 * 5 = 100 }
可使用 inline 内联函数替代有参数的宏定义,速度快的同时还能够检查参数类型。token
对于 C99 以后的版本,可使用常量定义来代替无参数的宏定义:
const double PI 3.14;
经过条件预处理指令,能够在预处理阶段控制要编译的代码,从而实现条件预编译。对编译器来讲这个步骤是透明的,它只须要编译全部它看见的代码便可。例如:
#include <stdio.h> #define DEBUG int main() { #ifdef DEBUG printf("debug info");// 只有定义了 DEBUG,才会执行这段代码 #endif printf("hello world\n"); return 0; }
固然,在文件中直接定义宏的话,每次都有修改源文件,不灵活。GCC 提供了一个指定宏定义的选项 gcc -D
,例如 gcc -DDEBUG -o build 1.c
会自动在代码中添加一段定义 DEBUG 的指令 #define DEBUG
,这样就能够在上面的源代码中删除 #define DEBUG
这一行了。
在宏体中(宏名中不可使用)可使用一个或两个 #
做为前缀。
示例:
#include <stdio.h> #define MY1(x) #x //传入的参数转为字符串 #define MY2(x) day##x //传入的参数自动拼接到 day 后面,例如出入1时为 day1 int main() { int day1 = 666; printf(MY1(abc\n)); // 打印 abc 字符串后换行 printf("%d", MY2(1));// 打印 666,即变量 day1 }