int f() {
static int i=0;
return ++i;
}
int g() {
return f() + f();
}
Run Code Online (Sandbox Code Playgroud)
是否g()返回3或者是结果undefined?
考虑这段代码:
#include <iostream>
typedef long xint;
template<int N>
struct foz {
template<int i=0>
static void foo(xint t) {
for (int j=0; j<10; ++j) {
foo<i+1> (t+j);
}
}
template<>
static void foo<N>(xint t) {
std::cout << t;
}
};
int main() {
foz<8>::foo<0>(0);
}
Run Code Online (Sandbox Code Playgroud)
在编译时clang++ -O0,它会在几秒钟内编译然后运行 4 秒。
然而,使用clang++ -O2,编译需要很长的时间和大量的内存。在Compiler Explorer上可以看到,更改8为较小的值后,它完全展开了循环。
我并不是让它完全没有优化,而是让它不递归,就像嵌套循环应该表现的那样。有什么我应该做的吗?
c++ clang compiler-optimization template-meta-programming loop-unrolling
有些人在需要没有计数器或计数器的循环时编写这样的代码n-1, ..., 0:
while (i--) { ... }
Run Code Online (Sandbox Code Playgroud)
一个具体的例子:
volatile int sink;
void countdown_i_used() {
unsigned i = 1000;
while (i--) {
sink = i; // if i is unused, gcc optimizes it away and uses dec/jnz
}
}
Run Code Online (Sandbox Code Playgroud)
在GCC 8.2(在Godbolt编译器资源管理器上),它被编译成
# gcc8.2 -O3 -march=haswell
.L2:
mov DWORD PTR sink[rip], eax
dec eax # with tune=generic, sub eax, 1
cmp eax, -1
jne .L2
Run Code Online (Sandbox Code Playgroud)
在clang(https://godbolt.org/z/YxYZ95)上,如果不使用计数器,它会变成
if(i) do {...} while(--i);
Run Code Online (Sandbox Code Playgroud)
但如果使用,就像GCC一样
add esi, -1
cmp …Run Code Online (Sandbox Code Playgroud) 它已经在这里讨论的是hypot比慢sqrt,因为它处理的情况下,当两个输入是巨大的或微小的,这样sqrt会错误地返回INF或0。
但是,根据一些测试,hypot甚至比先转换为更高的精度然后再进行琐碎计算再转换回来还要慢。
那么,在什么情况下我应该使用hypot?只有当没有更大的浮点类型和溢出是一个问题?
编辑:sqrtl并hypot在 input 上有所不同a=1,b=1.8e-8,但sqrtl返回更准确的结果:
hypot 1.0
sqrtl 1.000000000000000222044604925031
exact 1.000000000000000161999999999999986878000000000002125764000...
1+eps 1.0000000000000002220446049250313080847263336181640625
Run Code Online (Sandbox Code Playgroud)
确切线,其中的EPS被加入到结果示这里
使用g++.exe -m64 -std=c++17和任何优化级别进行编译,然后运行:
#include <iostream>
int main() {
const auto L1 = [&](){};
std::cout << sizeof(L1) << std::endl;
const auto L2 = [&](){L1;};
std::cout << sizeof(L2) << std::endl;
const auto L3 = [&](){L1, L2;};
std::cout << sizeof(L3) << std::endl;
const auto L4 = [&](){L1, L2, L3;};
std::cout << sizeof(L4) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出为1,8,16,24,这意味着L2包含1个引用,L3包含2个引用,L4包含3个引用。
但是,给定相同的功能“ [&](){L1, L2;}in main()”,的值&L1 - &L2应固定,并L1与L2x 的指针一起使用,在x86中直接[rbx+const]假定为rbx=&L2。为什么GCC仍然选择在lambda中包含所有引用?
.assert(x)应该表示x为真,因此编译器应该有权使用此信息进行优化.
例如,
char const* week(int n) {
assert (n>=0 && n<7);
switch (n) {
case 0: return "Sunday";
...
case 6: return "Saturday";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可以优化成
char const* week(int n) {
char const* const* const x = {"Sunday", ..., "Saturday"};
return x[n];
}
Run Code Online (Sandbox Code Playgroud)
并删除CMP n,7