代码之家  ›  专栏  ›  技术社区  ›  soandos

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

  •  1
  • soandos  · 技术社区  · 12 年前

    如果有一个函数不使用任何引用或指针作为参数,它的返回类型是未使用的,并且它不进行明显离开系统的调用(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 不必是相同的大小,但如果它们被定义为相同的大小的话,这必须起作用吗,还是仍然是未定义的行为?

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

    2 回复  |  直到 12 年前
        1
  •  1
  •   David Rodríguez - dribeas    12 年前

    该标准保证 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);
    

    编译器可以删除没有副作用的代码,但仅通过检查函数签名无法明确确定这些代码。对于内联函数,编译器可以看到代码,编译器有机会。对于在不同的翻译单元中定义的函数,事情有点困难(通过链接时间优化,如果函数是 足够小 ).

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

        2
  •  0
  •   Nepthar    12 年前

    我认为这属于“定义明确的未定义行为”的范畴;它会的 可能 一直在工作(假设sizeof(int*)==sizeof(int)),但它在技术上是未定义的,将来有可能被某些编译器完全破坏。另一个例子是使用并集将float的位重新解释为int。

    此外,如果我没有为您指明LLVM的链接时间优化方向,那我就大错特错了。它的目标是在链接时准确地完成您正在谈论的内容。它很棒,在osx上“开箱即用”。他们还有一个很好的、简单的例子来说明它是如何工作的: http://llvm.org/docs/LinkTimeOptimization.html