在C ++中强制执行语句顺序 [英] Enforcing statement order in C++
问题描述
假设我有一些语句,我想在
中执行固定顺序。我想使用g ++优化级别2,所以一些
语句可以重新排序。
考虑下面的例子。
using Clock = std :: chrono :: high_resolution_clock;
auto t1 = Clock :: now(); // Statement 1
foo(); //语句2
auto t2 = Clock :: now(); //语句3
auto elapsedTime = t2 - t1;
在此示例中,语句1-3在
中执行很重要,订购。但是,编译器认为语句2是不是
独立于1和3并执行代码如下?
using Clock = std :: chrono :: high_resolution_clock;
foo(); //语句2
auto t1 = Clock :: now(); //语句1
auto t2 = Clock :: now(); //语句3
auto elapsedTime = t2 - t1;
摘要 p>
似乎没有可靠的方法来防止重新排序,但只要链接时/全程序优化未启用,在单独的位置定位被调用的函数编译单元似乎是一个相当好的赌注。 (至少使用GCC,尽管逻辑意味着这可能与其他编译器一样。)这是以函数调用为代价的 - 内联代码是在同一个编译单元中定义的并且可以重新排序。
原始答案:
GCC会对-O2优化下的通话进行重新排序:
#include< chrono>
static int foo(int x)//'static'或不在这里不影响排序。
{
return x * 2;
}
int fred(int x)
{
auto t1 = std :: chrono :: high_resolution_clock :: now();
int y = foo(x);
auto t2 = std :: chrono :: high_resolution_clock :: now();
return y;
}
GCC 5.3.0:
$ b b
g ++ -S --std = c + + 11 -O0 fred.cpp
:
_ZL3fooi:
pushq%rbp
movq%rsp,%rbp
movl%ecx,16(%rbp)
movl 16(%rbp) ,%eax
addl%eax,%eax
popq%rbp
ret
_Z4fredi:
pushq%rbp
movq%rsp,%rbp
subq $ 64,%rsp
movl%ecx,16(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq%rax,-16(%rbp)
movl 16(%rbp) ,%ecx
call _ZL3fooi
movl%eax,-4(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq%rax,-32(%rbp)
movl -4 (%rbp),%eax
addq $ 64,%rsp
popq%rbp
ret
但:
g ++ -S --std = c ++ 11 -O2 fred.cpp
:
_Z4fredi:
pushq%rbx
subq $ 32,%rsp
movl%ecx,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
call _ZNSt6chrono3_V212system_clock3nowEv
leal(%rbx,%rbx),%eax
addq $ 32,%rsp
popq%rbx
ret
现在,使用foo()作为extern函数:
#include< chrono>
int foo(int x);
int fred(int x)
{
auto t1 = std :: chrono :: high_resolution_clock :: now();
int y = foo(x);
auto t2 = std :: chrono :: high_resolution_clock :: now();
return y;
}
g ++ -S --std = c ++ 11 -O2 fred.cpp
:
_Z4fredi:
pushq%rbx $ b b subq $ 32,%rsp
movl%ecx,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl%ebx,%ecx
call _Z3fooi
movl%eax,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl%ebx,%eax
addq $ 32,%rsp
popq%rbx
ret
但是,如果使用-flto(链接时优化)链接:
0000000100401710< main>:
100401710:53 push%rbx
100401711:48 83 ec 20 sub $ 0x20,%rsp
100401715:89 cb mov%ecx,%ebx
100401717:e8 e4 ff ff ff callq 100401700< _ _ main>
10040171c:e8 bf f9 ff ff callq 1004010e0< _ZNSt6chrono3_V212system_clock3nowEv>
100401721:e8 ba f9 ff ff callq 1004010e0< _ZNSt6chrono3_V212system_clock3nowEv>
100401726:8d 04 1b lea(%rbx,%rbx,1),%eax
100401729:48 83 c4 20 add $ 0x20,%rsp
10040172d:5b pop%rbx
10040172e:c3 retq
Suppose I have a number of statements that I want to execute in a fixed order. I want to use g++ with optimization level 2, so some statements could be reordered. What tools does one have to enforce a certain ordering of statements?
Consider the following example.
using Clock = std::chrono::high_resolution_clock;
auto t1 = Clock::now(); // Statement 1
foo(); // Statement 2
auto t2 = Clock::now(); // Statement 3
auto elapsedTime = t2 - t1;
In this example it is important that the statements 1-3 are executed in the given order. However, can't the compiler think statement 2 is independent of 1 and 3 and execute the code as follows?
using Clock=std::chrono::high_resolution_clock;
foo(); // Statement 2
auto t1 = Clock::now(); // Statement 1
auto t2 = Clock::now(); // Statement 3
auto elapsedTime = t2 - t1;
Summary:
There seems to be no guaranteed way to prevent reordering, but as long as link-time/full-program optimisation is not enabled, locating the called function in a separate compilation unit seems a fairly good bet. (At least with GCC, although logic would suggest that this is likely with other compilers too.) This comes at the cost of the function call - inlined code is by definition in the same compilation unit and open to reordering.
Original answer:
GCC reorders the calls under -O2 optimisation:
#include <chrono>
static int foo(int x) // 'static' or not here doesn't affect ordering.
{
return x*2;
}
int fred(int x)
{
auto t1 = std::chrono::high_resolution_clock::now();
int y = foo(x);
auto t2 = std::chrono::high_resolution_clock::now();
return y;
}
GCC 5.3.0:
g++ -S --std=c++11 -O0 fred.cpp
:
_ZL3fooi:
pushq %rbp
movq %rsp, %rbp
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
addl %eax, %eax
popq %rbp
ret
_Z4fredi:
pushq %rbp
movq %rsp, %rbp
subq $64, %rsp
movl %ecx, 16(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq %rax, -16(%rbp)
movl 16(%rbp), %ecx
call _ZL3fooi
movl %eax, -4(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq %rax, -32(%rbp)
movl -4(%rbp), %eax
addq $64, %rsp
popq %rbp
ret
But:
g++ -S --std=c++11 -O2 fred.cpp
:
_Z4fredi:
pushq %rbx
subq $32, %rsp
movl %ecx, %ebx
call _ZNSt6chrono3_V212system_clock3nowEv
call _ZNSt6chrono3_V212system_clock3nowEv
leal (%rbx,%rbx), %eax
addq $32, %rsp
popq %rbx
ret
Now, with foo() as an extern function:
#include <chrono>
int foo(int x);
int fred(int x)
{
auto t1 = std::chrono::high_resolution_clock::now();
int y = foo(x);
auto t2 = std::chrono::high_resolution_clock::now();
return y;
}
g++ -S --std=c++11 -O2 fred.cpp
:
_Z4fredi:
pushq %rbx
subq $32, %rsp
movl %ecx, %ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl %ebx, %ecx
call _Z3fooi
movl %eax, %ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl %ebx, %eax
addq $32, %rsp
popq %rbx
ret
BUT, if this is linked with -flto (link-time optimisation):
0000000100401710 <main>:
100401710: 53 push %rbx
100401711: 48 83 ec 20 sub $0x20,%rsp
100401715: 89 cb mov %ecx,%ebx
100401717: e8 e4 ff ff ff callq 100401700 <__main>
10040171c: e8 bf f9 ff ff callq 1004010e0 <_ZNSt6chrono3_V212system_clock3nowEv>
100401721: e8 ba f9 ff ff callq 1004010e0 <_ZNSt6chrono3_V212system_clock3nowEv>
100401726: 8d 04 1b lea (%rbx,%rbx,1),%eax
100401729: 48 83 c4 20 add $0x20,%rsp
10040172d: 5b pop %rbx
10040172e: c3 retq
这篇关于在C ++中强制执行语句顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!