为什么在visual studio中连续的int数据类型变量位于12个字节的偏移

Why are consecutive int data type variables located at 12 bytes offset in visual studio?

本文关键字:12个 字节 类型变量 int visual studio 为什么 连续 数据      更新时间:2023-10-16

为了澄清这个问题,请观察c/c++代码片段:

int a = 10, b = 20, c = 30, d = 40; //consecutive 4 int data values.
int* p = &d; //address of variable d.

现在,在visual studio(在2013年测试)中,如果p == hex_value的值(可以在调试器内存窗口中查看),那么,您可以观察到,其他变量a, b, c和d的地址各有12个字节的差异!

如果是p == hex_value,那么如下:

&c == hex_value + 0xC(注意十六进制C是十进制的12)

&b == &c + 0xC
&a == &b + 0xC 

那么,为什么有一个12字节的偏移量而不是4字节——int只是4字节?

现在,如果我们声明一个数组:

int array[]  = {10,20,30,40};

值10,20,30,40与预期的相差4个字节!

谁能解释一下这种行为?

标准c++在8.3.4 Arrays一节中声明"一个数组类型的对象包含连续分配的N个t类型的非空子对象集"。

这就是为什么array[]将是连续的int的集合,并且一个元素与下一个元素之间的差值将恰好是sizeof(int)。

对于本地/块变量(自动存储),没有这样的保证。唯一的语句在section 1.7中。c++内存模型:"每个字节都有一个唯一的地址。"c++对象模型:该对象的地址是它占用的第一个字节的地址。两个对象(…)应该有不同的地址"

所以你所做的一切假设这些对象的连续性将是未定义的行为和不可移植的。您甚至不能确定创建这些对象的地址的顺序。

现在我已经玩了修改版本的代码:

int a = 10, b = 20, c = 30, d = 40; //consecutive 4 int data values.
int* p = &d; //address of variable d.
int array[] = { 10, 20, 30, 40 };
char *pa = reinterpret_cast<char*>(&a), 
     *pb = reinterpret_cast<char*>(&b), 
     *pc = reinterpret_cast<char*>(&c), 
     *pd = reinterpret_cast<char*>(&d);
cout << "sizeof(int)=" << sizeof(int) << "n &a=" << &a << 
  " +" << pa - pb << "charn &b=" << &b << 
  " +" << pb - pc  << "charn &c=" << &c << 
  " +" << pc - pd << "charn &d=" << &d;
memset(&d, 0, (&a - &d)*sizeof(int));    
// ATTENTION:  undefined behaviour:  
// will trigger core dump on leaving 
// "Runtime check #2, stack arround the variable b was corrupted". 

当运行这个代码时,我得到:

debug                   release                comment on release
sizeof(int)=4           sizeof(int)=4       
 &a=0052F884 +12char     &a=009EF9AC +4char
 &b=0052F878 +12char     &b=009EF9A8 +-8char   // is before a 
 &c=0052F86C +12char     &c=009EF9B0 +12char   // is just after a !!
 &d=0052F860             &d=009EF9A4

所以你可以看到地址的顺序甚至可以在同一个编译器上改变,这取决于构建选项!!实际上,在释放模式下,变量是连续的,但顺序不同。

调试版本上的额外空格来自选项/rtc 。我故意用苛刻的memset()来覆盖变量,它假定它们是连续的。在退出执行时,我立即得到一条消息:"运行时检查#2,变量b周围的堆栈已损坏",这清楚地说明了这些额外字符的目的。如果删除该选项,您将得到MSVC13个连续变量,每个变量为4字节,正如您所期望的那样。但是也不会有更多关于堆栈损坏的错误消息。