Можете ли вы воспроизвести или объяснить эту ошибку 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
остановит компилятор от перемещения вызова.