在“#if”条件中是否允许使用“sizeof”?

sch*_*ine 5 c c-preprocessor

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

\n
#if sizeof(char) == 1\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n

clang\xe2\x80\x99s 输出:

\n
sizeof in preprocessor directive.c:1:5: error: function-like macro \'sizeof\' is not defined\n#if sizeof(char) == 1\n    ^\n1 error generated.\n
Run Code Online (Sandbox Code Playgroud)\n

gcc\xe2\x80\x99s 输出:

\n
sizeof in preprocessor directive.c:1:11: error: missing binary operator before token "("\n    1 | #if sizeof(char) == 1\n      |           ^\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

Wei*_*hou 8

它们都是正确的,您似乎误解了 cppreference 所说的内容。

\n

来自标准草案(N3096)6.10.1,有条件包含:

\n
\n

在求值之前,预处理标记列表中将成为控制常量表达式的宏调用将被替换(由定义的一元运算符修改的宏名称除外),就像在普通文本中一样。defined如果由于此替换过程而生成标记,或者使用定义的一元运算符与宏替换之前的两个指定形式之一不匹配,则行为未定义。在执行了由于宏扩展和defined宏表达式、has_include表达式、has_embed表达式和has_c_attribute表达式的求值而进行的所有替换后,除 true 之外的所有剩余标识符(包括词法上与关键字相同的标识符,例如 false)都将替换为 pp-number 0、true替换为 pp-number 1,然后将每个预处理标记转换为标记。生成的标记组成控制常量表达式,该表达式根据 6.6 的规则进行计算。

\n
\n

(强调我的)

\n

这意味着从预处理器的角度来看,在 的上下文中#ifsizeof(char)==1简单地替换为产生0(0)==1,因为这不是有效的常量表达式,程序格式错误,编译器应该发出诊断,而编译器实际上会执行此操作并且是因此符合。

\n

sizeof这里一点也不特别,也不是char。它们就像任何其他尚未被替换的标识符一样#defined,并被替换为 0。您可以通过以下方式自行测试#if sizeof *1#if char+1等内容自行测试。

\n

cppreference 引用没有错误。从你的链接来看,完整的句子是

\n
\n

该表达式是一个常量表达式,仅使用常量和标识符,使用#define 指令定义。任何非文字标识符、非使用 #define 指令定义的标识符,其计算结果为 \xe2\x80\x8b0。

\n
\n

这基本上与标准中的内容相同,并且它当然并不意味着您似乎认为“可以在此处使用任何常量表达式”。

\n

我想以上应该已经足以回答你的问题了。只是为了更清楚地表明,代码不可能像您期望的那样工作,正如评论指出的那样,处理发生sizeof在翻译的第 7 阶段,距离预处理的最后一个阶段,即第 4 阶段很久之后。非正式地,我只想假设这sizeof是由编译器处理的,而预处理器对此一无所知。无论你怎么说,在一个条件下都不可能sizeof(char)==1评估为真#if

\n