C 语言中以 # 开头的就是预处理指令,例如 #include 。
所有的预处理指令都会在 GCC 编译过程的预处理步骤解析执行,替换为对应的内容。在下一步编译过程中,看不到任何预处理信息,只需要对独立的程序文件进行操作即可。
例如,对于这个 C 文件:
#include <stdio.h> int main() { printf("file is:%s, function is:%s, line is:%d, %s, %s", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__); }执行结果如下:
file is:define.c, function is:main, line is:5, Jan 19 2019, 15:10:57预处理时,会把所有出现宏名的地方自动替换为对应的宏值。
#define 宏名 宏值宏定义的规则:
宏值中可以有其他宏的名字,预处理时也会被替换,例如: #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)); }可以带一个或多个参数。有参数的宏的原则是:
一切地方都有加括号,放在因为运算的优先级导致异常
整个宏值要加括号每个参数都有加括号 #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 内联函数替代有参数的宏定义,速度快的同时还可以检查参数类型。
对于 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 }转载于:https://www.cnblogs.com/kika/p/10851512.html
相关资源:数据结构—成绩单生成器