我把它插入Godbolt,惊喜地发现这两个函数调用a()
和b()
在-O0
以外的任何地方都是等效的(使用大多数主要编译器):
#include <cmath>
struct A {
int a,b,c;
float bar() {
return sqrt(a + b + c);
}
};
struct B {
int a[3];
float bar() {
int ret{0};
for (int i = 0; i<3; ++i) {
ret += a[i];
}
return sqrt(ret);
}
};
float a() {
A a{55,67,12};
return a.bar();
}
float b() {
B b{55,67,12};
return b.bar();
}
Godbolt输出为:
a():
movss xmm0, DWORD PTR .LC0[rip]
ret
b():
movss xmm0, DWORD PTR .LC0[rip]
ret
.LC0:
.long 1094268577
我不是装配专家,但我想知道这是否真的是真的,他们在做相同的工作。我甚至看不出这个程序集中哪里有对sqrt
的调用,或者long
"常量"是什么。
此函数:
float a() {
A a{55,67,12};
return a.bar();
}
具有与下面完全相同的可观察行为:
float a() {
return sqrt(55+67+12);
}
对于b()
也是如此。此外,sqrt(55+67+12) == sqrt(134) == 11.5758369028
.
IEEE-754浮点值11.5758369028
的二进制表示为01000001001110010011011010100001
。这个二进制的整数是1094268577
。
编译器应用所谓的as if规则将这两个函数替换为具有与原始代码完全相同的可观察行为的汇编:两个函数都返回值为11.5758369028
的float
。