我知道这不是使用void指针的好方法,但我很好奇这种行为。
int main()
{
void* ptr;
void* next;
ptr = ::operator new(8);
next = (void*)((char*)ptr + 1) ;
*(int*)next = 90;
*(int*)ptr =100;
cout << "Ptr = " << ptr<<endl;
cout << "Ptr-> " << *(int*)ptr<<endl;
cout << "Next = " << next<<endl;
cout << "Next-> " << *(int*)next<<endl;
}
---------------
Result :
Ptr = 0x234e010
Ptr-> 100
Next = 0x234e011
Next-> 0
---------------
在64位(x86_64)和32位(x86)平台(Linux和Windows)中,当向ptr添加超过4个字节时,90将保留在next指向的位置,但是当添加少于4时,
*当执行* ptr = 100时,下一个突然变为0,与calloc和malloc相同的结果
为什么要改变ptr点的内容必须改变ptr + 1点的内容?当我们超过4个字节时,为什么这不会发生?如果是关于内存对齐,为什么在32位和64位平台上都有相同的行为?
在delphi(windows 32bit / Embarcadero)中也有相同的结果
谢谢你,抱歉我的英文不好
答案 0 :(得分:3)
当您使用X86架构时,对齐不会成为问题:处理器可以访问未对齐的内存,即使它更慢。
英特尔处理器以最低有效字节FIRST存储数据。谷歌关于字节序以获得更深入的解释。会发生什么
vvvvvvvvvvvvvvvv this is Ptr
+===+===+===+===+===+===+===+===+
| |100| 0 | 0 | 0 | | | |
+===+===+===+===+===+===+===+===+
^^^^^^^^^^^^^^^^ this is next after you say '*next=100'
现在当你将90存储到* Ptr时,这会变为
vvvvvvvvvvvvvvvv this is Ptr
+===+===+===+===+===+===+===+===+
| 90| 0 | 0 | 0 | 0 | | | |
+===+===+===+===+===+===+===+===+
^^^^^^^^^^^^^^^^ this is next
所以接下来变为0,因为它的前3个字节被0覆盖,最后一个字节反正为0.
答案 1 :(得分:0)
整数(通常)为4个字节。你只是为ptr添加一个字节而不是4。这意味着ptr和下一个重叠,因此你的100的分配是破坏了90的最后一个字节(它发生了0)。
你需要:
next = (void*)((char*)ptr + sizeof(int));
实际上你需要使用正确输入的指针。
答案 2 :(得分:0)
似乎正在发生的事情是每次操作后八个字节的内存都有以下内容:
*(int*)next = 90; // 90 == 0x00 00 00 5A
--> 0x?? 5A 00 00 00 ?? ?? ??
*(int*)ptr = 100; // 100 == 0x00 00 00 64
--> 0x64 00 00 00 00 ?? ?? ??
因此,*(int*)next
现在等于零。请注意,您不能指望这种行为,因为它取决于底层硬件。
答案 3 :(得分:0)
这与分配或无效*无关,而与您对如何将值存储在内存中的假设有关。
你写了一个int,一个占用系统4个字节的单元,地址为101,然后写另一个地址为100,覆盖第一个值的3个。
不幸的是,您使用的系统不使用您假设的字节顺序/字节顺序,其中第一个值的lsb将占用地址104.结果是四个零字节中的一个来自你的第二次写入使第一个值为零。
这是因为你使用char偏移来调用未定义的行为来比特旋转int值。
当整数变为8个字节时,任何使用自己的指针手动操作的人都会遇到同样的问题。
顺便说一句,您应该能够告诉表单这个系统数字表示的单词顺序。