【问题标题】:Possible optimization for compilers or defined behaviour编译器或定义行为的可能优化
【发布时间】:2013-04-09 23:56:23
【问题描述】:

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

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

【问题讨论】:

  • @artlessnoise 这更像是stackoverflow.com/questions/15825188/… 之类的东西。此外,这不是死代码,这是什么都不做的活代码。
  • 不,我认为(如果我错了,请纠正我)你无法优化它。考虑 b 和 c 是具有共享指针的类的实例,这可能会受到影响。甚至考虑在离开作用域时调用析构函数。
  • @rralf 是有道理的。顺便说一句,行为是否已定义?
  • @soandos 维基百科的文章没有完全解释这一点,但是有许多编译器优化可以检测什么都不做的实时代码。那是死代码。请参阅 wikipedia 和 google 的参考部分。如果编译器研究没有涵盖它,那么我认为你的问题是深奥的。

标签: c++ c++11 undefined-behavior


【解决方案1】:

该标准保证 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】:

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

    另外,如果我没有向您指出 LLVM 的链接时间优化的方向,我会完全不妥。它旨在完全按照您在链接时谈论的内容。它很棒,并且在 osx 上“开箱即用”。他们还提供了一个很好的简单示例来说明其工作原理:http://llvm.org/docs/LinkTimeOptimization.html

    【讨论】:

      猜你喜欢
      • 2012-09-28
      • 1970-01-01
      • 2013-02-26
      • 2023-04-02
      • 2011-11-07
      • 2012-07-01
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多