【问题标题】:Undefined behaviour observed in C++/memory allocation在 C++/内存分配中观察到未定义的行为
【发布时间】:2016-10-25 07:05:00
【问题描述】:
#include <iostream>
using namespace std;
int main()
{
    int a=50;
    int b=50;
    int *ptr = &b;
    ptr++;
    *ptr = 40;
    cout<<"a= "<<a<<" b= "<<b<<endl;
    cout<<"address a "<<&a<<" address b= "<<&b<<endl;
    return 0;
}

上面的代码打印:

a= 50 b= 50
address a 0x7ffdd7b1b710 address b= 0x7ffdd7b1b714

而当我从上面的代码中删除以下行时

cout<<"address a "<<&a<<" address b= "<<&b<<endl;

我得到的输出为

a= 40 b= 50

我的理解是堆栈向下增长,所以第二个答案似乎是正确的。我不明白为什么 print 语句会弄乱内存布局。

编辑

我忘了说,我使用的是 64 位 x86 机器,操作系统为 ubuntu 14.04 和 gcc 版本 4.8.4

【问题讨论】:

  • 这只是未定义的行为
  • 在 VS2005 中不是这样。我在有和没有cout&lt;&lt;"address a " &lt;&lt; .. 行的情况下运行上面的代码,结果在两种情况下都是 a=50, b=50。

标签: c++ memory undefined-behavior


【解决方案1】:

首先,这都是未定义的行为。 C++ 标准规定,只有在数组边界(后面加上一个元素)中,您才能增加指针,标准布局类还有一些例外,但仅此而已。所以,一般来说,用指针窥探是未知的领域。

来到您的实际代码:由于您从不询问其地址,因此编译器可能只是将a 留在寄存器中,甚至直接将其作为常量传播到整个代码中。出于这个原因,a 从不接触堆栈,并且您不能使用指针破坏它。

无论如何请注意,编译器不限于按声明的顺序在堆栈上推送/弹出变量 - 它们会以它们看起来合适的任何顺序重新排序,实际上它们甚至可以在堆栈框架中移动(或替换)在整个函数中 - 函数中看似很小的变化可能会使编译器完全改变堆栈布局。因此,即使像您那样比较地址也没有说明堆栈增长的方向。

【讨论】:

  • 此外,即使在&amp;a 版本中,编译器也可以在第一行cout 中内联50
  • @melpomene:是的,也许他正在使用不是很激进的优化设置进行编译。
  • 我没有使用任何优化标志并同意这不是找到堆栈增长方向的方法。你们说的是有道理的,但它不应该像 b 在内存布局中堆叠在 a 之下 - 至少帽子是我们被教导的吗?我试图利用内存在程序/堆栈中的布局方式,而不是像数组和类那样完全受边界限制。我不能这样利用它吗?
【解决方案2】:

UB - 你获取了一个指向b 的指针,你移动了那个指针ptr++,这意味着你指向了一些未知的、未分配的内存,你试图在那个内存区域上写,这将导致未定义的行为。

在 VS 2008 上,逐步调试它会为您抛出这个非常不言自明的消息::

【讨论】:

  • 我正在使用 gdb,它不会抛出任何错误,我也一步一步去那里,但没有出现这种情况。
  • 你试过使用 Valgrind 吗?我认为这会有所帮助,但不确定。抛出的味精在这里并不重要。重要的是您正在尝试访问未分配给您的内存。
猜你喜欢
  • 2013-09-18
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2017-01-27
  • 2019-08-11
相关资源
最近更新 更多