【发布时间】:2014-10-04 02:55:18
【问题描述】:
当在发布模式下使用 Visual Studio Professional 2013 Update 3(32 位和 64 位选项)编译时,无论 N 的值如何,此 code example 都将输出 time: 0:
#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() 函数可以恢复正确的行为,但更改 t0、r 和 t1 的声明和初始化顺序不会。
【问题讨论】:
-
执行操作的时间可能低于 Windows 在调用 clock() 时使用的计时器的分辨率。我最近在这里写了一个答案,可能会让您了解在 Windows 上使用更高分辨率的计时器:stackoverflow.com/questions/25954602/ctimespan-always-gets-zero
-
这是一个优化问题(编译器认为调用 g 没有副作用),因此它实际上在调用
g之前将两个调用都设置为时钟。您应该可以通过将auto r = g();更改为volatile auto r = g();来解决此问题 -
@MichaelPetch 你的
volatile将阻止g在第二个clock之后移动,但你还需要一些东西来阻止它在第一个clock之前移动,例如:@987654338 @. -
@Paul 不,抱歉。将
g()视为计算 2+2 的东西。它可以在编译时计算,也可以在 main 开始时计算,或者在 2 个clock之间计算,你所知道的是它在存储到 r 之前已经计算过了。为了澄清事情,像volatile auto r = g();这样的声明不必保留在一个整体中。编译器首先将其拆分为auto tmp=g(); volatile auto r=tmp;,并且第一部分可以随心所欲地移动,因为它没有副作用并且不依赖任何东西。 -
@Paul 对。请注意,定义
n的这一行可以在第一个clock之前或之后,没关系。读取n的值是一个副作用,所以它不能与clock通勤。由于g取决于该值,因此g在读取后必须保留。
标签: c++ visual-studio-2013 std