你能用ctime重现或解释这个Visual C++错误吗

Can you reproduce or explain this Visual C++ bug with ctime?

本文关键字:Visual C++ 错误 解释 ctime      更新时间:2023-10-16

在发布模式下使用Visual Studio Professional 2013 Update 3编译时,无论N的值如何,此代码示例都将输出time: 0,包括32位和64位选项:

#include <iostream>
#include <functional>
#include <ctime>
using namespace std;
void bar(int i, int& x, int& y)  {x = i%13; y = i%23;}
int g(int N = 1E9) {   
  int x, y;
  int r = 0;
  for (int i = 1; i <= N; ++i) {
    bar(i, x, y);
    r += x+y;
  }
  return r;
}
int main()
{
    auto t0 = clock();
    auto r  = g();
    auto t1 = clock();
    cout << r << "  time: " << t1-t0 << endl;
    return 0;
}

当在rextester.com上使用gcc、clang和其他版本的vc++进行测试时,它表现正确,并输出大于零的time。有什么线索吗?

我注意到内联g()函数可以恢复正确的行为,但更改t0rt1的声明和初始化顺序则不能。

如果您使用调试器查看反汇编窗口,您可以看到生成的代码。对于处于发布模式的VS2012 express,您可以获得以下信息:

00AF1310  push        edi  
    auto t0 = clock();
00AF1311  call        dword ptr ds:[0AF30E0h]  
00AF1317  mov         edi,eax  
    auto r  = g();
    auto t1 = clock();
00AF1319  call        dword ptr ds:[0AF30E0h]  
    cout << r << "  time: " << t1-t0 << endl;
00AF131F  push        dword ptr ds:[0AF3040h]  
00AF1325  sub         eax,edi  
00AF1327  push        eax  
00AF1328  call        g (0AF1270h)  
00AF132D  mov         ecx,dword ptr ds:[0AF3058h]  
00AF1333  push        eax  
00AF1334  call        dword ptr ds:[0AF3030h]  
00AF133A  mov         ecx,eax  
00AF133C  call        std::operator<<<std::char_traits<char> > (0AF17F0h)  
00AF1341  mov         ecx,eax  
00AF1343  call        dword ptr ds:[0AF302Ch]  
00AF1349  mov         ecx,eax  
00AF134B  call        dword ptr ds:[0AF3034h]  

从汇编的前4行中,您可以看到对clockds:[0AF30E0h])的两次调用发生在对g的调用之前。因此,在这种情况下,g需要多长时间并不重要,结果只显示这两个顺序调用之间的时间。

VS似乎已经确定g没有任何会影响clock的副作用,所以可以安全地转移呼叫。

正如Michael Petch在评论中指出的那样,将volatile添加到r的声明将阻止编译器移动调用。