2

在下面非常简单的 C 程序中,预期的编译器错误是什么?gcc 给了我 1 而 MSVC 2013 给了我 2。

#define foo
#define bar (defined(foo))

#if bar
#error 1
#else
#error 2
#endif

我的问题希望同样简单:

  1. C 规范对defined() 的值有何规定?我似乎找不到任何关于将其值设置为另一个宏的内容。
  2. 实际代码不是我可以控制的,并且到处都在使用“#if bar”。更改#define 以使#if 栏在MSVC 中按“预期”工作的最简单方法是什么?我唯一能想到的就是扩展它:

.

#ifdef foo
#define bar 1
#else
#define bar 2
#endif
4

2 回答 2

2

C规范说:

§6.10.1/1 表达式 ... 可能包含以下形式的一元运算符表达式,或者defined identifier如果标识符当前定义为宏名称(即,如果它是预定义的或者它是没有具有相同主题标识符的干预指令的预处理指令),如果不是。defined(identifier)1#define#undef0

将成为控制常量表达式的预处理标记列表中的 §6.10.1/4 宏调用被替换(除了那些由defined一元运算符修改的宏名称),就像在普通文本中一样。如果此替换过程的结果生成了令牌defined,或者defined一元运算符的使用与宏替换之前的两种指定形式之一不匹配,则行为是 undefined。由于宏扩展和defined一元运算符的所有替换都执行完毕后,所有剩余的标识符(包括那些在词法上与关键字相同的标识符)都被替换为 pp-number 0,然后将每个预处理标记转换为一个标记。

(强调我的)但是,宏替换非常复杂,我认为 MSVC 定义foodefined(bar)未定义行为,而 GCC 定义foo1正确。由于 MSVC 处于未定义的行为,它会做一些奇怪的事情。

正如您所说,最简单的解决方法是

#ifdef foo
#define bar 1
#else
#define bar 2
#endif
于 2014-12-03T18:22:58.347 回答
0

我相信编译器会将名称/宏定义为名称/宏定义的一部分之后的所有内容,即作为程序文本,而不是宏文本。

int defined(char s);    // prototype of a function named "defined"

#define foo
#define bar defined(foo)

现在,程序文本中的任何地方的“bar”都将替换为对不带参数的 defined() 的调用(因为“foo”被定义为空)。

于 2014-12-03T19:22:37.133 回答