目录
一、预定义符号
在C语言中,有一些预定义符号(Predefined Symbols)是由编译器提供的,它们具有特殊的含义和功能。以下是C语言中的一些常见预定义符号:
__LINE__: 表示当前代码所在的行号。
__FILE__: 表示当前源文件的文件名。
__DATE__: 表示当前编译的日期,格式为"MMM DD YYYY",例如"Jul 29 2023"。
__TIME__: 表示当前编译的时间,格式为"HH:MM:SS",例如"10:30:36"。
__STDC__: 表示当前编译器是否符合C语言标准。如果定义了该符号,则表示编译器符合C语言标准;否则,表示不符合。
NULL: 表示空指针常量。
EOF: 表示文件结束符。
true 和 false: 表示布尔类型的真值和假值,C99引入了 <stdbool.h> 头文件来定义这两个符号。
这些预定义符号可以在代码中使用,例如用于调试、错误处理或条件编译等方面。
二、#define
在C语言中,#define
是一个预处理指令,用于定义宏(macro)。宏是一种将代码片段替换为预定义文本的机制。#define
指令的语法如下:
#define 宏名 值或代码片段
通过#define
指令定义的宏可以用于替代代码中的特定文本,从而简化代码编写、提高代码可读性和可维护性。
以下是几个常见的#define
的用法示例:
1、定义常量:
#define PI 3.14159
在上述示例中,PI
被定义为一个常量,它在代码中的所有出现都会被替换为3.14159
。
2、定义带参数的宏:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
上述示例定义了一个带有两个参数的宏MAX
,用于返回两个值中的最大值。在使用该宏时,编译器会将宏调用处的代码替换为宏定义中的代码。
例如,int max_value = MAX(10, 20);
在编译时会被替换为int max_value = ((10) > (20) ? (10) : (20));
3、条件编译:
#define DEBUG
在上述示例中,通过定义了DEBUG
宏,可以在代码中使用条件编译指令来控制是否包含调试相关的代码。例如:
#ifdef DEBUG
// 调试相关的代码
#endif
如果定义了DEBUG
宏,那么#ifdef
指令中的代码段会被包含在编译中,否则会被忽略。
注意:
- 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
- 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#和##在宏定义的使用
在C语言中,"#"和"##"符号在宏定义中具有特殊的作用:
"#":它是用于将宏参数转换为字符串的预处理器运算符。在宏定义中,可以使用"#"来创建字符数组的字符串字面量。例如:
#define STRINGIFY(x) #x
printf("%s", STRINGIFY(Hello)); // 打印 "Hello"
在上述示例中,宏STRINGIFY将其参数转换为字符串字面量。
#define PRINT(n,format) printf("the value of "#n" is "format"\n",n)
int main() {
int a = 10;
printf("the value of a is %d\n", a);
PRINT(a,"%d");
int b = 15;
printf("the value of b is %d\n", b);
PRINT(b,"%d");
float f = 4.5f;
printf("the value of f is %f\n", f);
PRINT(f,"%f");
return 0;
}
"##":它是用于连接两个标记(tokens)的预处理器运算符。在宏定义中,可以使用"##"进行标记的连接。例如:
#define CAT(x,y) x##y
int main() {
int ab = 2024;
printf("%d", CAT(a, b)); //打印2024
}
在上述示例中,宏CAT将标记a和b连接成一个新的标记ab,实际上相当于将a和b拼接成了一个变量名。
#define PRINT(n,format) printf("the value of "#n" is %"##format"\n",n)
int main() {
int a = 10;
printf("the value of a is %d\n", a);
PRINT(a, "d");
int b = 15;
printf("the value of b is %d\n", b);
PRINT(b, "d");
float f = 4.5f;
printf("the value of f is %f\n", f);
PRINT(f, "f");
return 0;
}
这个宏接受两个参数:n 和 format。它使用printf函数打印给定变量的值,并根据format参数指定的格式进行格式化输出。
在主函数main()中,首先定义了一个整型变量a,并使用printf函数直接打印了它的值。然后,通过PRINT宏打印了变量a的值,使用的格式为%d。
接下来,定义了一个整型变量b,并同样通过printf函数直接打印了它的值。然后,通过PRINT宏打印了变量b的值,同样使用的格式为%d。
最后,定义了一个浮点型变量f,并使用printf函数直接打印了它的值。然后,通过PRINT宏打印了变量f的值,使用的格式为%f。
整个代码的输出结果将会是:
the value of a is 10
the value of a is 10
the value of b is 15
the value of b is 15
the value of f is 4.500000
the value of f is 4.500000
其中,第一行是直接使用printf函数打印变量a的值;第二行是使用PRINT宏打印变量a的值;接下来的几行以此类推。
需要注意的是,预处理器指令和运算符在宏定义中的使用必须遵循一定的规则。例如,"#"运算符只能用于宏的参数,"##"运算符只能用于在宏定义中进行标记连接。
三、#undef
在C语言中,#define用于定义宏(macro),而#undef则用于取消定义之前定义的宏。可以使用#undef指令将一个已定义的宏从预处理器的符号表中删除。
下面是#undef指令的语法: #undef 宏名
其中,宏名是要取消定义的宏的名称。
以下是一个示例:
#define PI 3.14159 // 定义一个常量宏
#undef PI // 取消定义宏
在上述示例中,首先使用#define定义了一个名为PI的宏,其值为3.14159。然后,使用#undef取消了对PI的定义,从而将其从预处理器的符号表中移除。
在取消定义宏后,再次使用该宏名称将不再被替换。例如:
int radius = 5;
double circumference = 2 * PI * radius; // 编译错误,PI未定义
在上述示例中,由于宏PI已被取消定义,因此在计算周长时使用PI会导致编译错误。
使用#undef可以对已定义的宏进行有效的撤销操作,这在某些情况下可能是有用的,例如需要重新定义一个已存在的宏或避免冲突的宏定义等。
四、条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件 编译指令。
条件编译指令 | 说 明 |
---|---|
#if | 如果条件为真,则执行相应操作 |
#elif | 如果前面条件为假,而该条件为真,则执行相应操作 |
#else | 如果前面条件均为假,则执行相应操作 |
#endif | 结束相应的条件编译指令 |
#ifdef | 如果该宏已定义,则执行相应操作 |
#ifndef | 如果该宏没有定义,则执行相应操作 |
条件编译是一种在C语言中根据条件选择性编译代码的技术。它可以根据预定义的条件来决定是否包含或排除某些代码段,以实现在不同条件下进行编译。
条件编译使用预处理指令来实现,常用的预处理指令有以下几个:
-
#if
、#endif
和#else
:#if
指令用于根据条件表达式的值决定是否编译某段代码。#endif
指令标识条件编译块的结束。#else
指令用于在前面的条件为假时编译另一段代码。- 示例:
#if NUM > 100 printf("NUM is greater than 100."); #elif NUM < 0 printf("NUM is negative."); #else printf("NUM is between 0 and 100."); #endif
-
#ifndef
和#endif
:#ifndef
指令用于判断某个宏是否没有定义,若没有定义则编译#ifndef
和#endif
之间的代码。- 示例:
#ifndef DEBUG printf("Not in debug mode."); #endif
-
#elif
:#elif
指令在前面的条件为假时判断新的条件表达式是否为真,相当于“否则如果”。- 示例:
#if NUM > 100 printf("NUM is greater than 100."); #elif NUM < 0 printf("NUM is negative."); #elif NUM == 0 printf("NUM is zero."); #else printf("NUM is between 0 and 100."); #endif
-
#ifdef
和#endif
:#ifdef
指令用于判断某个宏是否已定义,若已定义则编译#ifdef
和#endif
之间的代码。- 示例:
#ifdef DEBUG printf("Debug mode enabled."); #endif
-
#if !defined
:#if !defined
指令用于判断某个宏是否没有定义,与#ifndef
相同的效果。- 示例:
#if !defined(DEBUG) printf("Not in debug mode. "); #endif
通过合理使用这些条件编译指令,可以根据不同条件选择性地编译不同的代码,实现灵活的编译控制,提高代码的可维护性和可移植性。请注意,在条件编译中,被排除的代码块将不会被编译和执行。