Wu *_*wei 6 c macros language-lawyer c-preprocessor preprocessor-directive
根据C11标准,类函数宏的参数可以在其预处理标记序列的开头或结尾包含空格.对于正常更换,这种空间没有任何影响.对于字符串化,应忽略空格,如6.10.3.2.2中所述
第一个预处理标记之前和构成参数的最后一个预处理标记之后的空格被删除.
(我相信这也证明了参数可以在它周围有空格.)问题是,对于可以通过##运算符连接的参数,编译器应该对它的空格做什么?
我用VC++试了一下,似乎只是忽略了空格.
我认为编译器应该用空格执行连接.这可能导致无效的令牌,例如,由标识符ABC形成的"ABC"和具有空白空间作为第一令牌的参数.根据该标准,如果以这种方式形成无效令牌,则行为是未定义的.
那么对于VC++之前所做的事情,它是否只是忽略空间或未定义行为的结果?
\n\n\n我相信这也是证明论证可以有空格的证据
\n
不,事实上它只是强化了标准的规定,即每个宏参数都是一系列预处理标记(C2011,6.10.3/11)。源文件中的空格分隔预处理标记;空格运行本身并不是预处理标记。
\n\n您引用的标准部分可能会令人困惑,因为它混合了级别——空白所属的源文件的字符序列,以及源序列的初始标记化产生的预处理标记序列。事实上,字符串化对于源字符序列中相邻标记是否由空格分隔很敏感,但任何此类空格的细节根本不重要——在字符串化时,由空格分隔的相邻标记将由单个空格分隔结果字符串中的字符。
\n\n这并不意味着预处理标记可以以空格开始或结束。不可以;完整详细信息请参见标准第 6.4 节。给定的实现如何满足字符串化规范必然是特定于实现的,但实现的一种方法是为每个预处理标记维护布尔标志,描述该标记在源序列中是否前面和/或后面有空格。然而,这些细节与解释标准为结果指定的内容无关,也与字符串化运算符和标记粘贴运算符无关。
\n\n\n\n\n对于由 ## 运算符连接的参数,编译器应该如何处理其空格?
\n
当##
操作员(或#
运算符)发挥作用时,编译器已经完成了它对源文件中出现的空格字符(直接)执行的所有操作,通过在将源标记化为预处理标记期间考虑它们。宏参数是预处理标记的序列,并且只有在这些标记可能是字符串或字符文字或标头名称的情况下,它们才可以包含空格。此外,该标准还规定:
\n\n\n如果在类函数宏的替换列表中,参数前面或后面紧跟着
\n##
预处理标记,则该参数将替换为相应的 argument\xe2\x80\x99s预处理标记序列[...]
(C2011,6.10.3.3/2;添加强调)
\n\n再次强调,空白运行不是预处理标记。宏观扩张#
和##
运算符处理预处理标记序列并在预处理标记序列的级别上进行操作。空白仅在此级别在标记内部表示。源文件中非预处理标记内部的空白仅在预处理标记序列中间接且不确定地表示。