【C语言】预定义符号,#define关键字及条件编译详解

目录

一、预定义符号

二、#define

三、#undef

四、条件编译


一、预定义符号

在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语言中根据条件选择性编译代码的技术。它可以根据预定义的条件来决定是否包含或排除某些代码段,以实现在不同条件下进行编译。

条件编译使用预处理指令来实现,常用的预处理指令有以下几个:

  1. #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
  2. #ifndef 和 #endif

    • #ifndef指令用于判断某个宏是否没有定义,若没有定义则编译 #ifndef 和 #endif 之间的代码。
    • 示例:
     #ifndef DEBUG
         printf("Not in debug mode.");
     #endif
  3. #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
  4. #ifdef 和 #endif

    • #ifdef指令用于判断某个宏是否已定义,若已定义则编译 #ifdef 和 #endif 之间的代码。
    • 示例:
     #ifdef DEBUG
         printf("Debug mode enabled.");
     #endif
  5. #if !defined

    • #if !defined指令用于判断某个宏是否没有定义,与 #ifndef 相同的效果。
    • 示例:
      #if !defined(DEBUG)
          printf("Not in debug mode. ");
      #endif

通过合理使用这些条件编译指令,可以根据不同条件选择性地编译不同的代码,实现灵活的编译控制,提高代码的可维护性和可移植性。请注意,在条件编译中,被排除的代码块将不会被编译和执行。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌岩雀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值