[英]Is it possible to define another preprocessor directive?
我一直在寻找代码高尔夫,并有一个想法尝试这个代码:
#define D #define
添加此行后,一切正常,但我将其扩展为:
#define D #define
D VALUE
在这里我得到了5个编译错误。 如果我把D
改成#define
一切都很好,有人可以解释,为什么这段代码是非法的?
注意:我使用的是VS2008编译器。
编辑:经过一些答案,我看到我需要给出编译错误列表:
第一个错误显示D
不仅仅是define
,还包括#
。
C 2011(N1570)6.10.3.4 3:“得到的完全宏替换的预处理标记序列不会被处理为预处理指令,即使它类似于一个......”
C ++ 2010(N3092)16.3.4 [cpp.rescan] 3具有完全相同的文本。
看起来您的预处理器正在进行您想要的替换,但您可能无法获得所需的行为 - 预处理器通常只是单个传递操作。 示例(使用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.
此代码是非法的,因为语言规范说它是非法的。 根据C和C ++预处理器规范,使用预处理器构建的任何代码都不会被解释为另一个预处理器指令。 简而言之,您无法使用预处理器构建预处理程序指令。 期。
(另外,您无法使用预处理器构建注释。)
这是行不通的,因为预处理是在一次通过中执行的。 例如,考虑下一个代码:
#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
预处理器眼中的代码行是预处理器语句(因此没有对它们进行任何替换)或正常的文本语句(并且已经完成替换)。 你不能同时拥有一个,所以一旦你'D'被替换,它只会查看是否还有更多的宏需要替换。 由于没有,它只是在C ++代码中留下'#define',然后C ++编译器在看到它时会出错(因为'#define'不是有效的C ++代码)。
所以更多地表明我的观点,这是预处理器的无效代码:
#define D define
#D value
因为预处理器不对预处理器语句进行任何宏替换,并且“#D”不是可识别的预处理器命令。 和这个:
#define D #define
D value
结果在这个C ++代码中:
#define value
这是无效的,因为预处理器已经完成运行。
查看16 [cpp]段1中的语法, 替换列表由pp-tokens组成,其中可包括生产#no-directive ,该指令在同一段的第2段中描述为
非指令不应以列表中出现的任何指令名开头。
也就是说,某种形式
#define NAME # define
恰好是非法的! 另请注意,此上下文中的#
不会将下一个单词转换为字符串: #
只会在#
函数样式宏中紧跟一个宏参数名后发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.