Можете ли вы воспроизвести или объяснить эту ошибку Visual C++ с помощью ctime?

Этот пример кода выведет time: 0 независимо от стоимости N при компиляции с Visual Studio Professional 2013 Update 3 в режиме выпуска, как 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;
}

При тестировании с gcc, clang и другой версией vC++ на rextester.com он работает правильно и выводит time больше нуля. Любые подсказки, что здесь происходит?

Я заметил, что g() функция восстанавливает правильное поведение, но изменяет объявление и порядок инициализации t0, r а также t1 не.

1 ответ

Решение

Если вы посмотрите на окно разборки с помощью отладчика, вы увидите сгенерированный код. Для 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 строк сборки вы можете увидеть, что два вызова clock (ds:[0AF30E0h]) случиться до звонка g, Так что в этом случае не имеет значения, как долго g занимает, результат покажет только время между этими двумя последовательными вызовами.

Кажется, В.С. определил, что g не имеет побочных эффектов, которые могли бы повлиять clock так что переставлять звонки безопасно.

Как отмечает Майкл Петч в комментариях, добавив volatile к объявлению r остановит компилятор от перемещения вызова.

Другие вопросы по тегам