【问题标题】:gcc optimization flag break codegcc 优化标志中断代码
【发布时间】:2013-05-09 12:11:37
【问题描述】:

当没有设置优化标志时,这段代码可以正常工作:

#include <cstdio>
int main(){
  float *ptr = ({float var[10] = {1,2,3,4,5,6,7,8,9,10}; var;});
  float *ptr1 = ({float var[10]; for(int i_=0;i_<10;i_++)var[i_]=i_+1; var;});
  float *ptr2 = ({float var[10]; var[4]=5; var;});
  printf("\n value = %f %f %f",ptr[4],ptr1[4],ptr2[4]);
}

它按预期返回5 5 5。 但是当优化标志被设置时,它返回5 0 5

ptr1 有与循环相关的问题。为什么? 也许它是一个错误?

我使用的是最新的 4.8.0,经过测试的 x64、x86 以及其他版本。所有相同的行为。

【问题讨论】:

  • 看起来像是指向过期临时对象的指针。
  • 是的,有未定义行为的味道。我不知道这是合法的,尽管如此,谢谢。
  • @chris 这是一个 GNU 语言扩展
  • 这是一个错误,在您的代码中。您不能返回堆栈对象的指针并在范围之外使用它。
  • @Cubbi,哦,谢谢。我没有意识到 -pedantic 在 Coliru 上默认是关闭的。

标签: c++ pointers optimization gcc


【解决方案1】:

您使用的是 GNU 语言扩展,所以让我们看看GNU documentation

在语句表达式中,在语句中创建的任何临时对象都会在语句结束时销毁。

var 每次都被销毁,指向其第一个元素(即表达式返回的内容)的指针不安全地取消引用。

【讨论】:

    【解决方案2】:

    var 指向的值在栈上分配。但是,var 的作用域是它包含在其中的括号。设置指向 var 的指针会导致未定义的行为。如您所见,在大多数情况下,堆栈中的值在您打印它们时并没有改变。但是,这可能会随着不同的优化设置而改变。这不是错误。这只是未定义行为的本质。

    【讨论】:

    • 所以如果我想要定义的行为必须在堆上分配它。但后来我总是要删除它。我认为我可以传递引用,就像在函数中一样,但它似乎在创建的堆栈上删除。奇怪的道氏,我认为它不应该是未定义的行为,因为返回确实是对 &var[0] 的引用
    • 这就是问题所在。记忆还在。您指向的内存可能没有发生任何事情。当数组在范围内时,它只是在堆栈中的某个位置。堆栈包含变量和指向程序中位置的指针的混合。当某些东西超出范围时,所有被压入堆栈的变量都会被弹出。随着新值被压入堆栈,这些值很快就会被覆盖。
    • 有没有办法不让弹出一个选定的?我的意思是,在没有堆解决方案的情况下从一个堆栈移动到另一个堆栈。就像我们在函数中所做的一样。当然标准删除在创建的堆栈上,但移动是不可能的?
    • 栈基本上只是一个非常大的数组。当你调用一个函数时,将当前程序状态写入栈顶。然后该函数可以将值写入堆栈。完成后,它将堆栈顶部移回并执行其余代码。尽管您的价值观没有改变,但它们无法受到保护。最终,堆栈将再次增长,它们将被覆盖。您可以做的是在程序的前面声明每个数组。这将允许您稍后在它们仍在范围内时访问它们。
    猜你喜欢
    • 2022-10-04
    • 2015-05-06
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2011-12-16
    • 2010-10-30
    相关资源
    最近更新 更多