【发布时间】:2020-07-25 09:28:51
【问题描述】:
阅读this 后,我有一个类似this one 的问题,想知道内存分配器如何在不违反严格的别名规则的情况下工作。但我并不想重新使用释放的内存,我想知道如何在不违反严格别名的情况下将分配的对象定位在线性内存中。
到目前为止,我看到的所有堆内存分配器都将它们的内存划分为某种块,前面有一个标题。然而,malloc 返回一个void * 并且通常指向紧接在头部之后的内存。这是一个非常缩小的示例来说明这一点。
#include <stddef.h>
struct block_header {
size_t size;
};
struct block_header *request_space(size_t size);
void *malloc(size_t size) {
struct block_header *block = request_space(size);
// I guess this violates strict aliasing, because the caller will
// convert the pointer to something other than struct block_header?
// Or why wouldn't it?
return block + 1;
}
我已经研究了一段时间,但我看不出分配器如何在不违反严格别名的情况下将其指针定位在内存区域中。我错过了什么?
【问题讨论】:
-
这不是分配器提供对齐的内存的原因之一,比如 16 字节吗?违规与 C 本身有关。
-
语言实现本身不必是可移植的。它可以依赖于实现细节。
-
位于
block + 1的内存还没有被malloc使用。所以严格的别名不适用。别名规则说“一个对象应该访问其存储的值 ...”,并且那里没有存储的对象。一旦客户端代码获取到指针并向其中写入一些东西,它就变成了存储的值,它的类型就变成了有效的类型。 -
@rici 谢谢,这确实可以解释很多!
-
许多标准库的内部结构依赖于 C 标准列出的定义不明确的行为或非标准扩展。例如,诸如 memcpy 之类的函数的各种优化通过读取对齐
uint32_t的数据来处理例如 32 位块,如果由普通 C 应用程序完成,这将是明显的严格别名违规。
标签: c pointers language-lawyer c11 strict-aliasing