为什么在 Visual Studio 中连续的 int 数据类型变量位于 12 个字节的偏移处?

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

To clarify the question, please observe the c/c++ code fragment:

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 个字节!

Now, in visual studio (tested on 2013), if value of p == hex_value (which can be viewed in debugger memory window), then, you can observe that, the addresses for other variables a, b, c, and d are each at a 12 byte difference!

所以,如果p == hex_value,那么它如下:

So, if p == hex_value, then it follows:

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

&c == hex_value + 0xC (note hex C is 12 in decimal)

&b == &c + 0xC

&a == &b + 0xC 

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

So, why is there a 12 bytes offset instead of 4 bytes -- int are just 4 bytes?

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

Now, if we declared an array:

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

值 10, 20, 30, 40 每个都按预期位于 4 个字节的差异!

The values 10, 20, 30, 40 each are located at 4 bytes difference as expected!

谁能解释一下这种行为?

Can anyone please explain this behavior?

推荐答案

标准 C++ 在 8.3.4 数组 部分声明,数组类型的对象包含一个连续分配的非-类型为 T 的 N 个子对象的空集."

The standard C++ states in section 8.3.4 Arrays that "An object of array type contains a contiguously allocated non-empty set of N subobjects of type T."

这就是为什么 array[] 将是一组连续的 int,并且一个元素和下一个元素之间的差异恰好是 sizeof(int).

This is why, array[] will be a set of contiguous int, and that difference between one element and the next will be exactly sizeof(int).

对于局部/块变量(自动存储),没有给出这样的保证.唯一的语句在 1.7 节中.C++ 内存模型:每个字节都有一个唯一的地址." 和 1.8.C++ 对象模型:该对象的地址是它占用的第一个字节的地址.两个对象 (...) 应具有不同的地址".

For local/block variables (automatic storage), no such guarantee is given. The only statements are in section 1.7. The C++ memory model: "Every byte has a unique address." and 1.8. The C++ object model: "the address of that object is the address of the first byte it occupies. Two objects (...) shall have distinct addresses".

因此,假设此类对象具有连续性,您所做的一切都将是未定义的行为且不可移植.您甚至无法确定创建这些对象的地址的顺序.

So everything that you do assuming contiguousness of such objects would be undefined behavior and non portable. You cannot even be sure of the order of the addresses in which these objects are created.

现在我已经使用了您代码的修改版本:

Now I have played with a modified version of your code:

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) << "
 &a=" << &a << 
  " +" << pa - pb << "char
 &b=" << &b << 
  " +" << pb - pc  << "char
 &c=" << &c << 
  " +" << pc - pd << "char
 &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". 

运行此代码时,我得到:

When running this code I get:

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

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

So you see that the order of the addresses may even be altered on the same compiler, depending on the build options !! In fact, in release mode the variables are contiguous but not in the same order.

调试版本上的额外空格来自选项 /RTCs.我故意用假设它们是连续的苛刻 memset() 覆盖变量.退出执行后,我立即收到一条消息:运行时检查 #2,变量 b 周围的堆栈已损坏",这清楚地表明了这些额外字符的用途.
如果您删除该选项,您将获得 MSVC13 连续变量,如您所料,每个 4 个字节.但是也不会再有关于堆栈损坏的错误消息.

The extra spaces on the debug version come from option /RTCs. I have on purpose overwritten the variables with a harsh memset() that assumes they are contiguous. Upon exit of the execution, I get immediately a message: "Runtime check #2, stack arround the variable b was corrupted", which clearly demonstrate the purpose of these extra chars.
If you remove the option, you will get with MSVC13 contiguous variables, each of 4 bytes as you did expect. But there will be no more error message about corruption of stack either.

相关文章