增量优化(Visual C Express 2010)

时间:2012-09-03 09:47:07

标签: c++ compiler-optimization visual-c++-2010-express

在使用Visual C ++ Express 2010处理C ++项目时,我发现了一个我想要理解的有趣问题。问题是如果我在Debug或Release模式下编译,我的程序结果会有所不同。我制作了一个小程序来重现它:

#include <stdio.h>


int firstarg(int i)
{
    printf("First argument called with i = %d\n", i);

    return i;
}

int secondarg(int i)
{
    printf("Second argument called with i = %d\n", i);

    return i;
}

void function(int i, int j)
{
    printf("Function called with %d, %d\n", i,j);
}

int main(int argc, char* argv[])
{

    // Line with the problem!
    for (int i = 0; i < 5; ) function(firstarg(i), secondarg(i++)); 

    return 0;
}

// Result on RELEASE:
Second argument called with i = 0
First argument called with i = 0
Function called with 0, 0
Second argument called with i = 1
First argument called with i = 1
Function called with 1, 1
Second argument called with i = 2
First argument called with i = 2
Function called with 2, 2
Second argument called with i = 3
First argument called with i = 3
Function called with 3, 3
Second argument called with i = 4
First argument called with i = 4
Function called with 4, 4

// Result on DEBUG
Second argument called with i = 0
First argument called with i = 1
Function called with 1, 0
Second argument called with i = 1
First argument called with i = 2
Function called with 2, 1
Second argument called with i = 2
First argument called with i = 3
Function called with 3, 2
Second argument called with i = 3
First argument called with i = 4
Function called with 4, 3
Second argument called with i = 4
First argument called with i = 5
Function called with 5, 4

如您所见,在这两种情况下,第二个参数在第一个参数之前进行评估(如果参数在某种LIFO堆栈中处理,我预期的那个参数);但在释放时,变量i的增量被“优化掉”并延迟到循环的下一次迭代。这是出乎意料的,我真的很想了解发生了什么。

当然,我可以通过将循环更改为

来轻松“修复”我的代码
    for (int i = 0; i < 5; ++i) function(firstarg(i+1), secondarg(i)); 

无论编译参数如何,都会给出相同的结果。但是,仍然,我真的想了解这种增量优化背后的原因。

PS。顺便说一句,我无法用linux下的gcc重现这个问题(使用-O0标志调试,使用-O3释放)。

3 个答案:

答案 0 :(得分:3)

你误解了结果。增量不会“优化掉”或延迟到循环的下一次迭代。在下一次迭代之前,您无法查看i的值是什么。试试这个:

for (int i = 0; i < 5; )
{
   function(firstarg(i), secondarg(i++)); 
   printf("At end of iteration, i = %d\n");
}

你会发现它根本没有延迟。

您的代码是UB,因为您可以访问变量并修改同一个变量而无需插入序列点。虽然你可能会得到非常疯狂的结果,但实际上你得到了两个“预期的”结果,这取决于你的优化。评估函数参数的顺序是未指定的。

答案 1 :(得分:2)

您的程序修改并读取变量i两次而没有插入序列点(在function的函数调用表达式中),这只是未定义的行为

答案 2 :(得分:0)

我认为你有一个导致未定义行为的序列点问题:

无论如何,解决方案是不要编写这种代码。

相关问题