将内存分配给void*时的gcc-calloc行为
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个字节时,90将保留在next指向的位置,但当添加小于4时,
*当*ptr=100将被执行时,next突然变为0,与calloc和malloc 的结果相同
为什么更改ptr点的内容必须更改ptr+1点的内容?当我们超过4字节时,为什么不发生ganna?如果是关于内存对齐,为什么在32位和64位平台上都有相同的行为?
在delphi(windows 32位/Enbarcadero)中也有相同的结果
谢谢你,很抱歉我的英语不好
当您使用X86体系结构时,对齐不会成为问题:处理器可以访问未对齐的内存,即使速度较慢。
英特尔处理器以最低有效字节FIRST存储数据。谷歌上关于endianness的内容可以得到更深入的解释。
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。
int(通常)为4个字节。您只向ptr中添加了一个字节作为next,而不是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*无关,而是与您对值如何存储在内存中做出假设有关。
您向地址101写入了一个int(系统中占用4个字节的单位),然后又向地址100写入了另一个int,覆盖了第一个值的3。
不幸的是,您使用的系统没有使用假设的尾数/字节排序,因此第一个值的lsb将占用地址104。结果是,第二次写入的四个零字节中的一个使第一个值为零。
这是因为您调用了未定义的行为,使用字符偏移量来位旋转int值。
当int变成8字节时,任何使用自己的指针操作的人都会遇到同样的问题。
顺便说一句,您应该能够从中了解系统数字表示的语序。
- 在其他容器中使用 boost::container::static_vector 时,GCC 编译错误"将'const s'绑定到类型's&'的引用丢弃限定符"
- 编译包含指向模板函数的指针的初始值设定项列表时,gcc 出错,但 clang 不出错
- 如何修复使用VScode调试器gcc调试时的"找不到文件"错误
- 在类中将不完整类型的unique_ptr初始化为 nullptr 时编译 gcc 错误
- 使用不同版本的 gcc 和 g++ 进行编译时出现问题
- 链接库时的默认目录上的GCC或G 路径搜索顺序
- 可能的 GCC 链接器错误会导致将弱符号和局部符号链接在一起时出错
- 使用GCC v4.8在Ubuntu 14.04上定义C 11中元组向量时的编译错误
- 当编译指向可能抛出的函数的非throwing时,gcc有什么问题吗
- 从值捕获的变量分配到lambda参数时,GCC编译器分割故障
- GCC:使用旧 C 代码时的链接器错误
- 使用gcc/g++/gdb/valgrind进行调试时的幻数
- 声明对引用类型的引用时出现 GCC 错误
- 将内存分配给void*时的gcc-calloc行为
- 编译一个相当简单的c++11程序时,gcc和clang之间的结果不同
- 在MinGW / GCC中编译tvmet库时的"::drem has not been declared"
- 当返回类型为类时,带有尾随返回类型的 GCC 属性警告
- 为什么当枚举或 int 值作为函数的参数传递时,gcc 没有发出警告?
- 通过引用和值传递时的GCC程序集
- 如何修复编译>2 GB代码时的GCC编译错误?