这个解释对于无法编译的C代码是否准确?

时间:2011-08-16 08:37:47

标签: c

涉嫌采访问答here

以下代码是否会编译(在C中)?

#define X 8;
int main(void)
{
    ++X; // will this line compile?
}`

我不是C的专家,但我知道一些C ++和思想:当然不是,你不能增加数字8,它是一个右值。当然,预处理器在尝试编译之前用X替换8,当它尝试编译时,它会因为这个原因而失败。然后,我是一个阅读面试问题网站,所以我想谁知道......

以下是给出的解释:

“严格地说,前缀(或后缀)增量运算符的操作数必须是不可修改的左值。现在我们知道左值是什么,我们必须问自己X是否是左值.X是一个宏,这意味着它不能识别内存中的位置 - 宏通过预处理器使用简单的文本替换。因为宏不存在于内存区域,所以它们不是左值。这意味着X不能用作操作数前缀增量运算符。因此,上面显示的代码将无法编译。“

这个解释是否像我认为的那样是无聊的?

您可以在上面找到多少错误?我想也许这应该是面试问题......

这很有趣:

“直观地说,您可能会说上面的代码无法编译 - 如果不确切知道原因。但是,在面试情况下,您需要提供一些如上所述的推理。简单的是或否答案只是不会在面试中削减它。“ (!)

5 个答案:

答案 0 :(得分:10)

给出的解释是错误的:

  

X是一个宏,这意味着它不能识别内存中的位置    - 宏通过预处理器使用简单的文本替换。

正是因为宏只是简单的文本替换,它们可以扩展到左值,或者其他任何东西。例如:

int x;
#define X x

int main() {
    ++X;
}

没关系。确实,宏本身在内存中没有位置,但这与++X;是否格式正确无关,因为++X;并不意味着“增加宏X”,这意味着“展开宏X,然后在前面粘贴++,在背面粘贴;,并对结果执行语法和语义分析。”

关于“宏”的解释是什么,它应该说整数常量8不是左值,这就是重要的事情。

有了这个改变,解释就可以了[编辑 - 正如Chris在评论中指出的那样,它仍然不行,它写道“前缀(或后缀)增量运算符的操作数必须是不可修改的左值“:应该是”可修改的“]

答案 1 :(得分:5)

  

这个解释是否像我认为的那样是无聊的?

  

“严格来说,前缀(或后缀)增量运算符的操作数必须是不可修改的左值...

什么?不可修改的左值类似于const int n; - 您可以获取其地址(通过&),但无法分配(通过=+=++)。你不能增加一些不可修改的东西。

引用标准(6.5.3.1第1段):

  

pre fi x增量或减量运算符的操作数应具有限定或   unquali fi ed real或指针类型,并且应该是一个可修改的左值。

咳咳。

  

X是一个宏,这意味着它不能识别内存中的位置 - 宏通过预处理器使用简单的文本替换。

这是假的。 C语言中不存在宏*。它们是预处理器的一部分,它没有左值,右值,表达式或内存的概念。 此特定宏扩展为整数常量,它是一个右值,但宏本身与上述任何一个都无关。有关作为左值的宏的反例,请参阅Steve Jessop's answer

正确的答案是该语句扩展为++8,并且由于8是一个右值,因此它不能用作++的参数(以任何一种形式),因此它不会编译。此外,根据您是否希望将此代码编译为C89或C99,将main保留为没有明确的return值可能会给出未定义的行为。

*如果这是接受的答案,我想我应该澄清这一点:预处理器 C编程语言的一部分。它在C标准中指定,并且编译器必须实现预处理才能成为C编译器。但是,C语言(即语法,语义,库等)不与预处理器交互 - 一旦你进入开始处理左值和右值的阶段,预处理器早就完成了所有宏都完全展开。 宏本身在语法中没有任何位置,因为它们不是“语言”的一部分。关于在这里使用“语言”一词是否具有误导性的问题存在争议(在Steve Jessop的回答中),并且我同意他的观点,即我找不到更好的词来代替使用。

答案 2 :(得分:2)

它的编译原因与以下完全相同:

8 = 8+1;

不会编译。

您无法修改(此处递增)常量。

答案 3 :(得分:2)

关于代码不能编译的解释是正确的,但在所有其他方面都是非常错误的。

它完全忽略了编译器看不到X的事实,它会看到++8;;,所以关于运算符是否可以应用于X的整个咆哮毫无意义。回答“不”比给出这样的解释要好得多。

答案 4 :(得分:0)

它不会编译,因为前缀运算符需要位置值。 8是一个常数,它失败了。您可以在此处进一步了解L值:L-Value and R-Value Expressions