根据CPPReference,#if后面跟一个常量表达式.sizeof是常量表达式中的有效运算符.但当我写下这段代码,并用clang或GCC编译时,它失败了:

#if sizeof(char) == 1
#endif

Cang的输出:

sizeof in preprocessor directive.c:1:5: error: function-like macro 'sizeof' is not defined
#if sizeof(char) == 1
    ^
1 error generated.

GCC的输出:

sizeof in preprocessor directive.c:1:11: error: missing binary operator before token "("
    1 | #if sizeof(char) == 1
      |           ^

是CPPReference错了还是编译器错了?

推荐答案

他们两个都是正确的,似乎您误解了cp首选项的含义.

从标准草案(N3096)6.10.1中,有条件地纳入:

在求值之前,将替换将成为控制常量表达式的预处理标记列表中的宏调用(定义的一元运算符修改的宏名称除外),就像在普通文本中一样.如果令牌defined是作为该替换过程的结果而生成的,或者在宏替换之前定义的一元运算符的使用与两个指定形式中的一个不匹配,则该行为是未定义的.在由于宏扩展和对defined个宏表达式的求值而进行的所有替换之后,已经执行了has_include个表达式、has_embed个表达式和has_c_attribute个表达式,all remaining identifiers other than true (including those lexically identical to keywords such as false) are replaced with the pp-number 0, true is replaced with pp-number 1,然后每个预处理令牌被转换为令牌.所得到的标记组成控制常量表达式,该常量表达式根据6.6的规则求值.

(重点是我的)

这意味着从预处理器的Angular 来看,在#if的上下文中,sizeof(char)==1被简单地替换为生成0(0)==1,因为这不是有效的常量表达式,程序的格式不正确,编译器应该发出诊断,编译器实际上会这样做,因此是一致的.

sizeof在这里一点都不特别,char也不是.它们就像任何其他不是#defined的标识符一样,并被替换为0.你可以自己测试#if sizeof *1#if char+1之类的东西.

Cpfirst的引语是正确的.从你的链接,完整的句子是

该表达式是一个常量表达式,仅使用常量和标识符,使用#DEFINE指令定义.任何非文字、非使用#DEFINE指令定义的标识符的计算结果为​0.

这基本上和标准中的陈述是一样的,它当然不意味着"任何常量表达式都可以在这里使用".

我想以上这些应该已经足够回答你的问题了.只是为了更清楚地说明,代码不可能像您期望的那样工作,正如注释所指出的那样,sizeof的处理发生在翻译的第七阶段,在预处理的最后阶段第四阶段之后很久.非正式地说,我只想说sizeof是由编译器处理的,预处理器对此一无所知.不管你怎么说,sizeof(char)==1都不可能在#if条件下求值为真.

C++相关问答推荐

初始化char数组-用于初始化数组的字符串是否除了存储数组的位置之外单独存储在内存中

segfault在C中使用getline()函数

GCC不警告隐式指针到整数转换'

如何在C宏中确定Windows主目录?

当execvp在C函数中失败时杀死子进程

当输入负数时,排序算法存在问题

C-使用指针返回修改后的整数数组

如何使解释器存储变量

I2C外设在单次交易后出现故障

S在本文中的价值观到底出了什么问题?

处理EPOLL_WAIT中的接收数据和连接关闭信号

Tic-tac-toe:从文件加载存储

按长度对argv中的单词进行排序

在C++中允许使用字符作为宏参数

如何在c中使用具有不同变量类型的内存分配?

如何在C中用bool进行文件I/O?

生成的头文件不包括用户定义的文件

计算时出现奇怪的计算错误;N Select K;在C中

保存有符号整数结果的变量是否会溢出(后增量的副作用),并且此后从未在任何表达式中使用过它,是否会导致 UB?

创建 makefile 来编译位于不同目录中的多个源文件