问题描述
要澄清这个问题,请观察c / c ++代码片段:
int a = 10,b = 20, c = 30,d = 40; //连续的4个int数据值。
int * p =& d; //变量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字节差异处! p>
任何人都可以解释这个行为吗?
标准C ++
这就是为什么, array []
将是一组连续的 int
一个元素和下一个元素之间的差异将恰好是sizeof(int)。
对于本地/块变量(自动存储),不提供此类保证。唯一的声明在 1.7节。 C ++内存模型:每个字节都有一个唯一的地址。和 1.8。 C ++对象模型:该对象的地址是它占据的第一个字节的地址。两个对象(...)应该有不同的地址。
所以你所做的一切假设连续性的对象将是未定义的行为和非便携式。您甚至不能确定创建这些对象的地址的顺序。
现在我使用了您的代码的修改版本:
int a = 10,b = 20,c = 30,d = 40; //连续的4个int数据值。
int * p =& d; //变量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));
//注意:未定义的行为:
//将在离开
时触发核心转储//运行时检查#2,堆栈arround变量b已损坏。
运行此代码时,我会得到:
调试版本发布评论
sizeof(int)= 4 sizeof(int)= 4
& a = 0052F884 + 12char& a = 009EF9AC + 4char
& b = 0052F878 + 12char& b = 009EF9A8 + -8char //在
之前& c = 0052F86C + 12char& c = 009EF9B0 + 12char //正好在一个 !!
& d = 0052F860& d = 009EF9A4
地址甚至可以在同一个编译器上更改,这取决于构建选项!实际上,在释放模式中,变量是连续的,但不是以相同的顺序。
调试版本上的额外空间来自选项。我有目的用一个苛刻的memset()覆盖变量,假设它们是连续的。退出执行时,我立即收到一条消息:运行时检查#2,堆栈变量b已损坏,这清楚地说明了这些额外字符的用途。
如果删除该选项,您将获得MSVC13连续变量,每个4个字节与您预期的一样。但是不会有更多关于堆栈损坏的错误消息。
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.
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!
So, if p == hex_value
, then it follows:
&c == hex_value + 0xC
(note hex C is 12 in decimal)
&b == &c + 0xC
&a == &b + 0xC
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};
The values 10, 20, 30, 40 each are located at 4 bytes difference as expected!
Can anyone please explain this behavior?
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."
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).
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) << "\n &a=" << &a << \
" +" << pa - pb << "char\n &b=" << &b << \
" +" << pb - pc << "char\n &c=" << &c << \
" +" << pc - pd << "char\n &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.
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.
这篇关于为什么连续int数据类型varaiables位于12个字节偏移在visual studio?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!