将内存分配给void时的gcc calloc行为*

时间:2013-12-08 19:23:05

标签: c++ c gcc

我知道这不是使用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)中也有相同的结果

谢谢你,抱歉我的英文不好

4 个答案:

答案 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个字节时,任何使用自己的指针手动操作的人都会遇到同样的问题。

顺便说一句,您应该能够告诉表单这个系统数字表示的单词顺序。