C++博客 :: 首页 ::  :: 联系 ::  :: 管理

一个语言细节问题

Posted on 2006-09-11 19:01 chenger 阅读(717) 评论(3)  编辑 收藏 引用 所属分类: Programming Stuff
这回还是一个语言细节问题:求值顺序,副作用等等。说白了和v[i]=i++是差不多的。不关心这类细枝末节的朋友们可以不用看了。

程序如下:

#include <iostream>

int
g(int i)
{
    return i;
}

int main()
{
    int i = 1;
    std::cout << i*g(i++);
    return 0;
}

起因是csdn上的一个帖子。我本来认为这是一个和实现有关的问题,属于标准中未指定行为的那一类。在求值i*g(i++)时,左序和右序都是有可能的,结果分别为1和2。在我的Visual C++ 2005 Express上跑,结果是1,而g++ 3.4.2的结果为2。VC 2005相当狠,把i的自增一直排到了整个std::cout << i*g(i++);的后面!

而那个帖子里给的程序是这样的(一看感觉就很像那些计算机等级考试的鸟题目)

#include <iostream>

int f(int n)
{
    if(++n == 5)
        return n++;
    return n*f(n++);
}

int main()
{

    std::cout << f(
1);
    return 0;
}

歧义或者说问题也是n*f(n++)这一句。我拿Visual C++ 2005 Express和g++ 3.4.2分别跑了一下,结果是120(对应于左序)和300(右序)。但csdn上有人拿VS 2005 Team版和VC 6.0测试,结果都是300。打死我都不相信VS 2005 Team和Visual C++ 2005 Express的C++编译器会有什么差别。而且我尝试了好几个可能有影响的编译选项,例如优化,是否禁用语言扩展(/Za),以及release和debug,结果都是120。我机子上没有VS 2005 Team,所以没办法验证。谁能告诉我这到底是怎么一回事?

Update:终于找了一台有Visual Studio 2005 Team Suite的机器来验证上面的程序,和我的Express版运行结果完全相同。但是还是有不少朋友说他们测试的结果是300。此外,还有的是在debug下结果为300,而release下结果是120!简直乱套了。

结论:得归功于csdn网友ugg的反复测试。关键问题是Visual C++编译器的运行时检查选项。默认情况是/RTCs,即stack frame run-time error checking,此时运行结果是120;如果打开了/RTCu,msdn上的解释是Reports when a variable is used without having been initialized,那么结果就是300。可见,在没有打开/RTCu的时候,编译器把n++这个副作用放到了整个full-expression的后面,可能是因为编译器认为n++对表达式的求值没有影响。至于左序右序的问题,我仍然难以下结论。在打开了/RTCu的情况下,不管是n*f(n++)或f(n++)*n结果都是300,否则结果都是120。

我的想法是:编译器之所以敢这么优化(这并不算是太大的优化),前提就是这个求值顺序本来就是unspecified,编译器可以自由发挥。当然,左序右序的问题可能不是那么关键。这仍然是一个依赖于编译器实现的问题,而不是语法问题。

Feedback

# re: 一个语言细节问题  回复  更多评论   

2006-09-12 09:14 by 梦在天涯
我的在vs2005中,debug和release中都是120啊,



这个运算符的执行顺序,每个编译器是不同的啊,这个很正常的


也有可能vs中可以设置她的顺序,是从左到右,或从右到左.到我没有找到资料,那位找到,也来这里给大家share一下,thx!

# re: 一个语言细节问题  回复  更多评论   

2006-09-12 12:55 by chenger
问题好像是自增运算符到底在什么时候被求值

# re: 一个语言细节问题  回复  更多评论   

2006-10-24 11:17 by 五点半
等级考试中的烂题真是比比皆是。一次参加职称考试,明显一个解引用野指针,还让写运行结果!

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理