C语言预处理器主要分为6个方面,分别是条件编译指令、包含指令、宏替换指令、控制指令、文件名和行信息指令、诊断信息指令等。前两篇介绍了条件变编译指令和编译器控制指令#pragma的组合参数,今天将介绍诊断指令、文件名和行信息指令以及相关的预定义宏等。
诊断指令:#error和#warning#error现代主流的编译器都已经支持,用法也非常简单,就是在编译阶段如果触发该条预处理指令,就会编译中断,输出自定义的error message。下面是一个简单的演示代码,如果TEST_ERR没有定义,就执行#error指令,输出预设的自定义error message,并中断编译。
这是visual studio 2022,vc编译器(c17版本)的编译截图:
图1
这是CLion2023,MinGW(gcc编译器,c23版本)的编译截图(注意红框里的代码c1189,后面要讲到):
#warning是C语言标准在C23里正式引入的,作用是在编译器阶段根据情况触发这条指令,输出自定义的warning message,但是不中断编译,只起到警告作用。很多编译器都已经默认支持了,比如在CLion2023里,无论我用的版本是c11、c17、c23都可以使用,代码和编译效如下:
但是在visual studio 2022里,因为最高的c标准就是c17,所以不能使用,即使引入了c23,微软是否支持,也搞不清楚。不过目前可以用上一篇文章中我介绍过的#pragma message指令来替代,我们可以来实验下:
出现一个错误代码,这个错误代码在MSDN里明确给出了解释:
说明VC编译器不支持,如果支持的话,比如#error指令,给出的代码是C1189,MSDN里的解释就能看到是支持的,并给出了指令的含义:
行号和文件名指令c语言把一些重要的环境变量、系统常量,用符号常量的形式进行封装,这样我们只需要使用定义好的宏名,就可以方便的获取系统环境的数据。比如__FILE__就表示当前源文件的绝对文件名(包含绝对路径和完整文件名)。形如”C:\PATH\FILE.EXT”就是绝对文件名,”C:\PATH”就是绝对路径,”file.ext”就是完整文件名,相对路径、文件名、扩展名(后缀)、根目录、父目录、当前目录等概念此处不展开。
一般情况下,这些预先定义好的宏在所有翻译单元都可以直接使用。 预处理器会在编译之前替换为具体的值。 预定义宏不带参数,不能重新定义。
预定义宏的知识我们在后面会详细讲述,现在我们先介绍__LINE__和__FILE__预定义宏,注意,前后分别是两个下划线!__LINE__预定义的是所在行的行号,整型常量,__FILE__预定义的是当前文件的绝对文件名。我们通过代码来演示下:
#include <stdio.h>
int main() {
printf("当前文件名:%s\n",__FILE__);
printf("当前行号:%d\n", __LINE__);
printf("当前行号:%d\n", __LINE__);
}
代码运行后,__FILE__输出的是绝对文件名,第一个__LINE__所在的是源文件中第4行,第二个__LINE__是第5行,运行效果如图:
这个功能非常非常方便,可以帮我们快速定位出错的代码是哪一行,也可以统计整个程序的代码行数。#line预处理指令有2个功能,比如:#line n,可以重新指定下一行的行号为n,并影响后面所有行的行号,n必须是大于0的整数常量。#line n “newfilename.ext”,可以在指定下一行行号时将__FILE__的值修改为“newfilename.ext”,注意,仅仅只是修改了__FILE__的值。下面是演示代码,为了代码排列变形(百家号没有代码块功能),只能贴图:
有几个细节需要注意,空行和注释都会被__LINE__统计,#line n中的n可以用__LINE__,表示下一行的行号变为__LINE__的值,n只能是整数常量,不能是表达式。运行效果如图:
预定义宏前面已经介绍了2个预定义宏__LINE__和__FILE__,现在我们再介绍几个重要的预定义宏的用法:
__STDC_VERSION__
long 类型的整数常量,其值表示C 标准的每个版本的年份。
__DATE__
字符串字面量,表示程序运行时的当前月份。
__TIME__
字符串字面量,表示程序运行时的当前时间。
__STDC_UTF_16__
__STDC_UTF_32__
C11新增了类型char16_t和char32_t,用来支持16位和32位的字符。若 char16_t 使用 UTF-16 则为1,若 char32_t 使用 UTF-32 则为1。
演示代码如下:
#include <stdio.h>
int main() {
printf("当前C标准: %ld\n", __STDC_VERSION__);
printf("当前日期: %s\n", __DATE__);
printf("当前时间: %s\n", __TIME__);
}
程序运行结果截图如下:
C标准的预定义宏有很多,例如__STDC__、__STDC_HOSTED__、__STDC_ISO_10646__等等,有兴趣的朋友可以查阅详细文档进行了解,也可以私信我赠送电子版C标准文档。
下期我们重点介绍下宏替换。
段誉,写于合肥。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved