17 February 2014

《程序员面试宝典》中看到这么一个问题:

下面C++代码的输出结果是什么?

C/C++ code
int i = 1;
void main()
{
	int i = i;
}

A. main()里的i是一个未定义值。 B. main()里的i值为1。 C. 编译器不允许这样的写法。 D. main()里的i值为0。

给你几分钟想想,答案到底是什么?

书中给出的答案是A,即i是一个未定义的值(请忽略那万恶的void main)。还有一小段解释,我们暂且不看这些,去试验一下,到底答案是否是未定义。

如果你的答案是一大串莫名其妙的值,那么恭喜你,得出的答案是未定义,那是因为局部变量没有被初始化,指向了某段地址。但是有个重要的地方没有说明,就是你的编译环境是什么。也许是linux下的Gcc编译器。

很不幸,我使用的Mac下的Clang编译器,得出的答案却是0。岂不是要选择D了么?

我们来简要分析一下,这两种情况出现的原因。虽然全局变量是i,但是局部变量i(编程时不要把全局变量和局部变量定义为同名变量)在函数中屏蔽掉了全局变量i,所以这里i值根本没有被初始化为1,而是指向了分配给局部变量的一段地址。“屏蔽”事实上也没有说明这到底是如何做到的。我们知道,编译器要把C语言的全局变量解析为符号(在可重定位目标文件中),这些符号在运行时被栈来管理。而局部变量被定义后,压在栈中,运行时,操作系统应该先在栈中寻找定义的局部变量i,如果没有在寻找全局变量i。自此完成了屏蔽的工作。

那么为什么两种情况会出现不同的结果?这大概就是由不同的环境下引起的。我想大概Clang想自动为局部变量进行初始化,以此避免局部变量未被初始化的错误。所以,这道题的答案要根据具体的编译环境来判定

如果真的希望答案是B,即函数中使用这个全局变量i,该如何做?在C++中可以如此使用:

int i = ::i;

如此,在函数中打印出的i值即为1(记得使用G++编译器)。

Ken Thompson和Dennis Ritchie这两位大神,在设计C语言时,不仅造就了它的成功,也引入了它的缺陷。而对于这些非黑即白的问题(如今天说到的这道题),对于现代的计算机科学发展,早已有很多工具可以避免(或弥补)这些缺陷了。所以,当你遇到这种似乎有固定答案的问题时,记得要考虑它的编译环境(甚至是运行环境)。



blog comments powered by Disqus