我的目标是制作一个通用的Arena分配器,在可执行文件的.bss部分存储一个缓冲区,以避免在实际程序中进行任何分配,但是这在C语言中存在严格别名的问题.如果我将缓冲区定义为static char buffer[BUFFER_SIZE];,那么通过严格的别名,我不能使用指向它的另一种类型的指针而不会导致未定义的行为.因为我希望这个分配器是泛型的,所以我需要能够在其中分配任何类型.

我不能使用memcpy(),因为分配器需要返回一个可以以任何方式使用的指针,而不是值的副本.我也不能使用基于union的类型双关,因为如果我没有弄错的话,它不会通过指针工作(参见第二个代码块here).

我知道在C中解决这个问题的唯一方法是使用-fno-strict-aliasing标志完全禁用严格别名.在this blog post中,作者试图做同样的事情,但他得到的解决方案是使用内联汇编来"清洗"指针,这样优化器就不能应用严格的别名优化,但这似乎非常脆弱.

有没有更好的方法来做这样的事情?理想情况下,应该有一个内置的,它允许清楚地标记要被严格别名忽略的类型转换或内存区域.

推荐答案

将分配代码放在与使用它的代码(客户端代码)分开的模块中.然后,只要您使用不执行跨模块优化的传统编译器和链接器进行构建,别名就必然会因为构建工具的独立模块性质而不是C标准的要求而起作用.(分配代码本身需要遵守别名规则.

这样做的原因是,当编译分配 routine 的某些客户端代码时,编译器只看到客户端代码而不是分配代码.它无法知道分配代码使用的声明类型.在编译客户端代码之后,你可以将它与你的分配 routine 链接起来,或者假设你可以将它与其他代码链接起来,在这些代码中,分配代码返回的所有地址都声明了与它们的用途匹配的类型,或者与其他代码链接起来,在这些代码中,分配代码返回的所有地址都是由C标准定义的malloc而不是你自己的代码提供的.由于客户端代码could与该其他代码链接,编译器必须生成一个对象模块,该模块与它一起工作,如C标准所指定的.然而,从接口的Angular 来看,分配代码的行为和这另一个代码的行为是相同的:客户端代码调用分配 routine 并接收指针,或者调用释放 routine 并提供指针,以此类推.因此,当编译器生成与其他标准一致的代码一起工作的代码时,它也必须与您的实际分配代码一起工作.

C++相关问答推荐

如何确保内存分配在地址附近?

为什么静态说明符为内联函数生成外部定义?

在C语言中使用scanf()时我无法理解的警告

自定义应用程序上的日志(log)轮换问题

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

加密解密工作正常,但返回错误0x80090005

对于C中给定数组中的每个查询,如何正确编码以输出给定索引范围(1到N)中所有数字的总和?

什么是.c.h文件?

无法在OpenGL上绘制三角形

处理EPOLL_WAIT中的接收数据和连接关闭信号

获取前2个连续1比特的索引的有效方法

被调用方函数内部的C-Struct变量,它是指针还是无关紧要

可以';t从A9G模块拨打电话

在同一范围内对具有相同类型的变量执行的相同操作在同一C代码中花费的时间不同

";错误:寄存器的使用无效;当使用-masm=intel;在gcc中,但在AT&;T模式

C 语言中 CORDIC 对数的问题

传递参数:C 和 C++ 中 array 与 *&array 和 &array[0] 的区别

使用复合文字数组初始化的指针数组

窗口消息处理函数以某种方式更改了应保持不变的 int 变量的值

将帧从相机 (/dev/video0) 复制到帧缓冲区 (/dev/fb0) 会产生意外结果