预定义
include
指令是一种常用的预处理指令。通过include
指令,可以将其他文件中的代码引入到当前文件中,从而实现代码的复用和模块化开发。
include
通常用于包含.h
的头文件,尽管可以包含.c
文件,但是这是错误的操作。
include
包含的文件会在预编译时展开,所以当一个.c
文件被包含,将会出现多次展开,从而导致函数重复定义,而.h
文件如果被多次包含,也会出现多次声明的情况。
用尖角号包含头文件,在系统指定的路径下找头文件
用双引号包含头文件,现在当前目录下找头文件,如果当前目录下不存在,再到系统指定的路径下找头文件
宏定义
在预编译时预处理器会将替换为对应的值,其格式是如下,其中宏名是一个标识符,值可以是一个常量、关键字、一段表达式或者函数,当某个值被宏名定义后,在代码中就可以直接用宏名来取代值
宏定义中的常量替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <stdio.h>
#define __NUMBER_1__ 12
int main() { int num1 = __NUMBER_1__; printf("num1 = %d\n", num1);
#undef __NUMBER_1__
#define __NUMBER_1__ 10
#define __STRING_1__ "str1" num1 = __NUMBER_1__; printf("num1 = %d\n", num1);
char* str1 = __STRING_1__; printf("str1 = %s\n", str1); return 0; }
#undef __NUMBER_1__ #undef __STRING_1__
|
宏定义中的关键字替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <stdio.h>
#define st static
st int num;
int main() { num = 10; printf("num = %d\n", num); return 0; }
#undef st
|
宏定义中的表达式替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
#define over return 0;
int main() { printf("hello world"); over }
#undef over
|
宏定义中的函数替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <stdio.h>
#define ex extern
#define fun function()
ex char* function();
int main() { printf("%s\n",fun);
return 0; }
char* function() { return "hello world"; }
#undef fun
|
带参数的宏定义替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
#define S(a,b) a+b;
int main() { int sum = S(1, 2); printf("sum = %d", sum); return 0; }
#undef S(a,b)
|
条件编译
通过条件编译预处理指令,可以根据条件判断是否编译某段代码
#if…#elif…#else…#endif
首先判断#if
后的条件,条件不满足则判断#elif
后的条件,均不满足则执行#else
,并以#endif
结束条件编译
下面代码中defined(宏名)
用于判断某个宏名是否被定义过,被定义过返回1
,否则返回0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h>
#define __DEBUG__
char* model;
int main() {
#if defined(__DEBUG__) model = "调试模式"; #elif defined(__RELEASE__) model = "发布模式"; #else model = "错误"; #endif printf("%s\n", model); return 0; }
|
#ifdef…#else…#endif
首先判断#ifdef
后的宏名是否被定义,未被定义则执行#else
,并以#endif
结束条件编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <stdio.h>
#define __RELEASE__
char* model;
int main() {
#ifdef __RELEASE__ model = "发布模式"; #else model = "调试模式"; #endif printf("%s\n", model); return 0; }
|
#ifndef…#else…#endif
与#ifdef
相对应,首先判断#ifndef
后的宏名是否未被定义,被定义则执行#else
,并以#endif
结束条件编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <stdio.h>
char* model;
int main() {
#ifndef __RELEASE__ model = "发布模式"; #else model = "调试模式"; #endif printf("%s\n", model); return 0; }
|
防止复引用
当一个.h
的头文件被#include
多次包含时,头文件中的声明语句将会被多次声明,使用选择编译的方式可以防止这种情况,使头文件在第二次被展开时不编译声明语句
如下代码,当.h
的头文件第一次被引用时,宏名PROJECT_NAME_DEMO_H
是未定义状态,代码体将会被展开编译,当头文件被第二次引用时,PROJECT_NAME_DEMO_H
已经被定义,代码体不被展开编译
1 2 3 4 5 6
| #ifndef PROJECT_NAME_DEMO_H #define PROJECT_NAME_DEMO_H
...
#endif
|