[英]gcc calloc behavior when allocating memory to void*
我知道这不是使用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个字节时,next指向的位置将保留90,但是当添加少于4个字节时,
*执行* ptr = 100时,* next突然变为0,与calloc和malloc相同
为什么要更改ptr point位置的内容必须更改ptr + 1 point的位置? 为什么当我们超过4个字节时这种情况不会发生? 如果是关于内存对齐的,为什么在32位和64位平台上都有相同的行为?
在delphi中也相同的结果(Windows 32bit / Embarcadero)
谢谢,抱歉我的英语不好
当您使用X86体系结构时,对齐将不会成为问题:即使速度较慢,处理器也可以访问未对齐的内存。
英特尔处理器以最低有效字节FIRST存储数据。 Google对字节序进行了更深入的解释。 发生的是
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
所以next变为0,因为其前3个字节被0覆盖,而最后一个字节始终为0。
ints(通常)为4个字节。 您仅向ptr的下一个字节添加了一个字节,而不是4。这意味着ptr和next重叠,因此您分配100会破坏90的最后一个字节(恰好是0)。
你需要:
next = (void*)((char*)ptr + sizeof(int));
实际上,您只需要使用正确键入的指针即可。
似乎正在发生的事情是,每次操作后,内存的八个字节具有以下内容:
*(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
现在等于零。 请注意,您不能指望此行为,因为它取决于基础硬件。
这与分配或void *无关,与您对值如何存储在内存中的假设无关。
您将一个int(在系统中占4个字节的单元)写入地址101,然后又将另一个写入地址100,覆盖第一个值3。
不幸的是,您所使用的系统未使用您假设的字节序/字节顺序,由此第一个值的lsb将占据地址104。结果是,第二次写操作的四个零字节之一使第一个值零。
这是因为您使用char偏移量调用tint int值来调用未定义的行为。
当int变为8个字节时,任何使用自己的指针手动操作的人都会遇到相同的问题。
顺便说一句,您应该能够以此形式告诉您有关系统数字表示形式的词序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.