我一直在查看code golf并想出了尝试此代码的信息:
添加此行后, #define D #define
一切正常,但我将其扩展为:
#define D #define
D VALUE
在这里我得到了5个编译错误。如果我将D
更改为#define
一切正常,有人可以解释一下,为什么这段代码是非法的?
注意:我使用的是VS2008编译器。
编辑:经过一些回答,我看到我需要提供编译错误列表:
第一个错误表明D
不仅仅是define
,还包括#
。
答案 0 :(得分:31)
C 2011(N1570)6.10.3.4 3:“生成的完全宏替换的预处理标记序列不会作为预处理指令处理,即使它类似于一个,......”
C ++ 2010(N3092)16.3.4 [cpp.rescan] 3具有完全相同的文本。
答案 1 :(得分:11)
看起来您的预处理器正在进行您想要的替换,但您可能无法获得所需的行为 - 预处理器通常只是单个传递操作。示例(使用clang,但您应该能够使用适当的VS2008标志进行重现):
$ cat example.c
#define D #define
D VALUE
$ cc -P -E example.c
#define VALUE
#define VALUE
直接进入编译器,编译器不知道如何处理它 - 毕竟它是一个预处理器指令。作为参考,Clang的错误与您的错误类似:
$ cc -c example.c
example.c:2:1: error: expected identifier or '('
D VALUE
^
example.c:1:11: note: expanded from macro 'D'
#define D #define
^
1 error generated.
答案 2 :(得分:10)
此代码是非法的,因为语言规范称这是非法的。根据C和C ++预处理器规范,使用预处理器构建的任何代码都不会被解释为另一个预处理器指令。简而言之,您无法使用预处理器构建预处理程序指令。期。
(另外,您无法使用预处理器构建注释。)
答案 3 :(得分:6)
这不起作用,因为预处理是在一次通过中执行的。例如,考虑下一个代码:
#define MYDEFINEWEIRD #define
MYDEFINEWEIRD N 6
int main() {
return 0;
}
预处理后,您的代码将如下所示:
#define N 6
int main() {
return 0;
}
和“#define”不是C或C ++上的有效语法。此外,由于不会处理生成的预处理程序指令,因此它不会解析代码中对“N”宏的后续引用。
只是为了好玩,您可以使用g ++ / gcc从命令行调用预处理器两次。考虑下一个代码(define.cpp):
#include <iostream>
#define MYDEFINEWEIRD #define
MYDEFINEWEIRD N 6
using namespace std;
int main() {
cout << N << endl;
return 0;
}
然后你可以这样做:
$ g++ -E define.cpp | g++ -o define -x c++ - && ./define
并输出:
6
答案 4 :(得分:1)
预处理器眼中的代码行是预处理器语句(因此没有对它们进行任何替换)或普通文本语句(并且已完成替换)。你不能同时拥有一个,所以一旦你'D'被替换,它只会查看是否还有更多的宏需要替换。由于没有,它只是在C ++代码中留下'#define',然后C ++编译器在看到它时会出错(因为'#define'不是有效的C ++代码)。
所以更多地说明我的观点,这是预处理器的无效代码:
#define D define
#D value
因为预处理器不对预处理器语句进行任何宏替换,并且“#D”不是可识别的预处理器命令。这个:
#define D #define
D value
此C ++代码中的结果:
#define value
这是无效的,因为预处理器已经完成运行。
答案 5 :(得分:1)
查看16 [cpp]段落1中的语法,替换列表由 pp-tokens 组成,其中可能包含生产 #no-directive ,在同一段的第2段中描述
非指令不得以列表中出现的任何指令名开头。
即形式
#define NAME # define
恰好是非法的!另请注意,此上下文中的#
确实不将下一个单词转换为字符串:#
之后的引用仅在#
被立即跟随时发生通过函数式宏中的宏参数名称。