是否可以定义另一个预处理器指令?

时间:2013-08-27 20:16:53

标签: c++ c c-preprocessor preprocessor-directive

我一直在查看code golf并想出了尝试此代码的信息:

添加此行后,

#define D #define一切正常,但我将其扩展为:

#define D #define
D VALUE

在这里我得到了5个编译错误。如果我将D更改为#define一切正常,有人可以解释一下,为什么这段代码是非法的?

注意:我使用的是VS2008编译器。

编辑:经过一些回答,我看到我需要提供编译错误列表:

  1. 错误C2121:'#':无效字符:可能是宏扩展的结果
  2. 错误C2146:语法错误:缺少';'在标识符'VALUE'之前
  3. 错误C4430:缺少类型说明符 - 假定为int。注意:C ++不支持default-int
  4. 错误C2144:语法错误:'void'前面应加';'
  5. 错误C4430:缺少类型说明符 - 假定为int。注意:C ++不支持default-int
  6. 第一个错误表明D不仅仅是define,还包括#

6 个答案:

答案 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

恰好是非法的!另请注意,此上下文中的#确实将下一个单词转换为字符串:#之后的引用仅在#被立即跟随时发生通过函数式宏中的宏参数名称。