C++ 您能否复制或解释此Visual C++;和我在一起?
当在发布模式下使用Visual Studio Professional 2013 Update 3编译时,无论C++ 您能否复制或解释此Visual C++;和我在一起?,c++,visual-studio-2013,std,C++,Visual Studio 2013,Std,当在发布模式下使用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;} in
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;
}
#包括
#包括
#包括
使用名称空间std;
空条(inti,int&x,int&y){x=i%13;y=i%23;}
int g(int N=1E9){
int x,y;
int r=0;
对于(int i=1;i如果您使用调试器查看反汇编winddow,您可以看到生成的代码。对于处于发布模式的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]
00AF1310推式edi
自动t0=时钟();
00AF1311呼叫dword ptr ds:[0AF30E0h]
00AF1317 mov edi,eax
自动r=g();
自动t1=时钟();
00AF1319呼叫dword ptr ds:[0AF30E0h]
执行此操作的时间可能低于调用clock()时Windows使用的计时器分辨率。我最近在这里写了一个答案,可能会让您了解在Windows上使用更高分辨率计时器的想法:这是一个优化问题(编译器认为调用g没有副作用)因此,它实际上会在调用g
之前将这两个调用置于时钟。您应该能够通过将auto r=g();
更改为volatile auto r=g()来解决此问题;
@MichaelPetch你的volatile
会阻止g
在第二个时钟之后移动,但是你也需要一些东西来阻止它在第一个时钟之前移动,例如:volatile n=42;volatile auto r=g(n);
@Paul No,对不起。想想g()
作为计算2+2的东西。它可以在编译时计算,也可以在main开始时计算,或者在2时钟之间计算,您所知道的只是它在存储到r中之前已经计算过了。为了澄清问题,可以使用类似于volatile auto r=g()的语句
不必保持完整。编译器首先将其拆分为auto tmp=g();volatile auto r=tmp;
第一部分可以随意移动,因为它没有副作用,也不依赖于任何东西。@Paul right。请注意,定义n
的这一行可以在第一个时钟之前或之后,这无关紧要。读取n
的值是一个副作用,因此它不能与clock
。由于g
取决于该值,g
必须在读取后保留。将r
标记为volatile
可能足以让编译器更改该行为。我希望这会起作用volatile auto r=g()
合法吗?根据这个推理,几乎所有的计算都不会影响时钟
,因此它可以被编译器移动到任何地方,但这绝对是一种疯狂。@MichaelPetch你是对的-就是这样-我会在答案中加上它。@MichaelPetch有一个合理的预期,即用户观察到的情况与此相同实际上,有一个要求。我只是查了C++编程语言,第四版,在第225页上读到:编译器可以重新排序代码以提高性能,只要结果与简单的执行顺序相同,那么调用你所经历的优化是合理的。bug.Volatile关键字的存在是为了向编译器提示不应该对变量(值、指针等)进行此类优化。使用优化会带来此类陷阱。这通常是大多数编译器允许您关闭某些优化或设置不同级别的原因。