为什么预处理器命令必须作为第一个非空格字符开始

3
我试图在一个setter行的中间进行#ifndef,但是我收到了以下错误提示:“Error 20 error C2014: preprocessor command must start as first nonwhite space”。
我知道这个错误的意思,但我很好奇为什么会这样?这是编译器的选择吗?这背后的原因是什么?这是为了让用户更容易注意到吗?
如果有人想知道代码,请看下面:
inline void SetSomething(int value) { #ifndef XBOX ASSERT(value <= 1); #endif test = value; };

你能展示一下触发这个错误的代码吗? - Borgleader
当然我已经添加了它,但我不确定是否有其他解决方法。 - marsh
3
对于像#define这样的东西,如果没有换行符,预处理器如何知道何时结束#define替换呢? - cdhowie
1
解决方法是在代码中添加换行符。inline函数定义不必在单独一行上。 - Keith Thompson
整个C/C++预处理器在多个方面都是邪恶的。无论如何,尽可能少地在C++中使用它,并且只以惯用方式使用。在C++中,优先使用模板来替代你在C中使用预处理器的许多情况。 - hyde
显示剩余5条评论
3个回答

5
起初,C语言没有标准的预处理器。后来人们开始使用预处理作为外部工具。你可能会注意到,在Unix-land shell脚本中,#与一般注释相同。
随着语言的发展,预处理器与编译器集成,成为语言本身的一部分,但它保持着完全不同的结构,尤其是它是面向行的,而C和C ++核心语言是自由格式的。
之后,界限变得更加模糊。现在,预处理通常添加#line指令或相当于核心语言编译器的指令,还有#pragma指令用于核心语言编译器,而在另一个方向上,我们现在有了_Pragma(如果我没记错的话)。 仍然,结构大多与最初相同。 C和C ++是进化的语言,而不是设计的语言。

我认为_Pragma实际上不是一个预处理器的东西,所以它不属于“另一个方向”。那个另一个方向其实也不太方便,因为编译的阶段。 - MSalters
@MSalters: _Pragma 的目的是可用于宏中(因为在宏中无法使用诸如 #pragma 之类的预处理器指令)。因此,它是朝着另一个方向发展的,是核心语言支持预处理器的一部分。相对于 #pragma,后者是预处理器支持核心语言的一部分。 - Cheers and hth. - Alf
@Cheersandhth.-Alf:但是_Pragma不支持预处理器。实际上,它与预处理器没有任何关系。#pragma也不是真正的预处理指令---它只是具有看起来像是预处理指令的语法(如果它是预处理指令,那么它怎么能影响诸如对齐之类的事情呢?)。 - Tim Čas
@TimČas:《C++标准》将#pragma列为预处理器指令。在C++98、C++03、C++11和C++14(迄今为止的所有标准)中,它被命名为“Pragma directive”,位于第16节“Preprocessing directives”中的§16.6。让我们认同标准对于正式术语的定义是正确的。这样做后,我们可以认同#pragma无法通过单独的纯文本预处理完全处理。这也是我想表达的大部分内容。 - Cheers and hth. - Alf

2

查看标准(第16节“预处理指令”),以#作为第一个非空白字符开始,就是按定义创建预处理指令的方法。

预处理指令由满足以下约束条件的一系列预处理令牌组成: 序列中的第一个令牌是#预处理令牌,在翻译阶段4的开始时,它要么是源文件中的第一个字符(可选地跟在不含换行符的空格后面),要么跟在至少包含一个换行符的空格后面。


1
如果你想知道最重要的原因,那就是因为标准这么规定了。
如果你想知道为什么标准这么规定,那是获取必要功能的最简单方法。 请记住,预处理和编译是两个完全独立的任务,预处理器对其输出的语言一无所知。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接