2014-10-04 2 views
6

Diese code example ausgeben wird time: 0 unabhängig vom Wert von N wenn mit Visual Studio Professional 2013 Update 3 im Release-Modus kompiliert, sowohl 32 als auch 64-Bit-Option:Können Sie diesen Visual C++ - Fehler mit ctime reproduzieren oder erklären?

#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; 
} 

Wenn mit gcc, Klirren und anderer Version getestet von vC++ auf rextester.com verhält es sich korrekt und gibt time größer als null aus. Irgendwelche Hinweise, was hier vor sich geht?

Ich bemerkte, dass inlining die g() Funktion richtige Verhalten wieder her, sondern Deklaration und Initialisierung der Reihenfolge der wechselnden t0, r und t1 nicht.

+3

Wahrscheinlich ist die Zeit, um den Vorgang durchzuführen, unter der Auflösung des Timers, den Windows beim Aufruf von clock() verwendet. Ich habe vor kurzem eine Antwort hier geschrieben, die Ihnen eine Idee der Verwendung von Höherauflösungstimern unter Windows geben könnte: http://stackoverflow.com/questions/25954602/ctimespan-always-gets-zero –

+0

Versuchen Sie N = 2147483646 und sehen Sie, ob das a macht Unterschied. –

+0

@MichaelPetch _Zeit, um die Operation durchzuführen, ist unter der Auflösung des Timers_ - es ist nicht der Fall, ich versuchte große 'N', wo es einige Sekunden dauert, um' f() 'auszuführen. –

Antwort

9

Wenn Sie den Disassembly winddow mit dem Debugger betrachten, können Sie den generierten Code sehen. Für VS2012 im Release-Modus auszudrücken erhalten Sie diese:

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] 

aus den ersten vier Zeilen der Montage können Sie vor dem Aufruf sehen, dass zu g passieren die beiden Anrufe zu clock (ds:[0AF30E0h]). In diesem Fall spielt es keine Rolle, wie lange g dauert, das Ergebnis zeigt nur die Zeit an, die zwischen diesen beiden aufeinanderfolgenden Aufrufen verstrichen ist.

Es scheint, VS hat festgestellt, dass g hat keine Nebenwirkungen, die clock beeinflussen würde, so dass es sicher ist, die Anrufe herum zu bewegen.

Wie Michael Petch in den Kommentaren hervorhebt, wird durch das Hinzufügen von volatile zur Deklaration von r der Compiler daran gehindert, den Aufruf zu verschieben.

+1

Das Markieren von "r" als "flüchtig" würde wahrscheinlich ausreichen, damit der Compiler dieses Verhalten ändert. Ich würde erwarten, dass dies funktionieren würde. Volatile auto r = g(); –

+0

Ist es legal? Nach dieser Überlegung beeinflussen fast alle Berechnungen nicht die "Uhr", so dass sie durch den Compiler irgendwohin verschoben werden könnte, aber es wäre ein reiner Wahnsinn. –

+0

@MichaelPick Sie sind richtig - das tut es - ich werde es in der Antwort hinzufügen. –

Verwandte Themen