可能对编译器或已定义行为进行优化

Possible optimization for compilers or defined behaviour

本文关键字:优化 定义 编译器      更新时间:2023-10-16

如果有一个函数不接受任何引用或指针作为参数,它的返回类型是未使用的,并且它不进行明显离开系统的调用(I/O调用,更改系统时间等),它是否保证只修改定义它的类(或根本不修改)?

我能想到的唯一例外情况如下:

void a(int b, int c){
    *((int*)b) = c; }
int main() {
    int d=1;
    a((int)(&d),d+1);
    return 0; }

保证被定义吗?我知道int*int不必是相同的大小,但如果它们被定义为相同的大小,这必须起作用吗,或者它仍然是未定义的行为?

目的是看一个函数是否可以合法地优化出来(即,如果你能证明它没有副作用,它可以被删除)。

标准保证用于从指针转换为合适的整型(大到足以容纳所有值)并返回到原始指针类型的reinterpret_cast保证产生相同的指针值。是的,这是可以保证的:

int *p = new int(5);
intptr_t i = reinterpret_cast<intptr_t>(p);
// ...
int *q = reinterpret_cast<int*>(i);
assert(p == q);
*q = 10;
assert(*p == 5);

编译器允许删除没有副作用的代码,但不能通过检查函数签名来清楚地确定。对于内联函数,编译器对代码具有可见性,编译器有机会。对于在不同的翻译单元中定义的函数来说,事情有点困难(如果函数足够小,那么使用链接时间优化仍然是可行的)。

请注意,这不仅限于通过值或const引用接受实参的函数。如果编译器看到一个函数通过引用修改了的实参,但它可以证明修改后的对象的值永远不会再被读取,那么理论上它可以删除该调用。另一方面,除了简单的情况,我不会打赌编译器会这样做。

我认为这属于"定义良好的未定义行为";它可能会一直工作(假设sizeof(int*) == sizeof(int)),但它在技术上是未定义的,并且将来某些编译器可能会完全破坏它。另一个例子是使用联合将浮点数的位重新解释为int型。

另外,如果我没有指出LLVM的链接时间优化方向,那我就大错特错了。它的目的是做你在链接时谈论的事情。它很棒,在osx上"开箱即用"。他们也有一个很好的简单的例子来说明它是如何工作的:http://llvm.org/docs/LinkTimeOptimization.html