【发布时间】:2019-02-15 15:29:43
【问题描述】:
我正在编写一个 Arena Allocator,它可以工作,但我觉得它违反了严格的别名规则。我想知道我是对还是错。这是代码的相关部分:
typedef struct ArenaNode ArenaNode;
struct ArenaNode {
ArenaNode *next;
size_t dataSize;
u8 data[];
};
typedef struct {
ArenaNode *head;
ArenaNode *current;
size_t currentIndex;
} Arena;
static ArenaNode *ArenaNodeNew(size_t dataSize, ArenaNode *next)
{
ArenaNode *n = malloc(sizeof(ArenaNode) + dataSize);
n->next = NULL;
n->dataSize = dataSize;
return n;
}
void *ArenaAlloc(Arena *a, size_t size)
{
const size_t maxAlign = alignof(max_align_t);
size_t offset = nextHigherMultiplePow2(offsetof(ArenaNode, data), maxAlign) - offsetof(ArenaNode, data);
size_t dataSize = offset + max(size, ARENA_SIZE);
// first time
void *ptr;
if (a->head == NULL) {
ArenaNode *n = ArenaNodeNew(dataSize, NULL);
a->head = n;
a->current = n;
ptr = n->data + offset;
a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
} else {
// enough space
if (a->currentIndex + size <= a->current->dataSize) {
ptr = &a->current->data[a->currentIndex];
a->currentIndex = nextHigherMultiplePow2(a->currentIndex + size, maxAlign);
} else {
ArenaNode *n = ArenaNodeNew(dataSize, NULL);
a->current->next = n;
a->current = n;
ptr = n->data + offset;
a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
}
}
return ptr;
}
Arena 是 Node 的链表,Node 是一个标头,后跟数据 u8 data[]。 u8 是无符号字符。
我维护下一个可用索引 (currentIndex) 并按此索引推进 data 并将其返回为 void * (ptr = &a->current->data[a->currentIndex])。这是否违反了严格的别名规则,因为我正在将指向 u8 的指针转换为其他东西并使用它?
我的困惑来自于 malloc 返回的内存没有有效类型。但是由于我将 malloc 的指针转换为 ArenaNode * 并在分配它(在 ArenaNodeNew 中)之后设置它的数据成员(next 和 dataSize),因此有效类型变为 ArenaNode。或者是吗?我没有设置 data 字段。
基本上,我认为问题可以简化为:如果我 malloc 内存区域的大小为 10,则将指针转换为 struct {int a;} *(假设 4 字节 int),将其设置为 a,什么剩下的 6 个字节会发生什么?它有任何有效的类型吗?灵活数组成员的存在是否会对此产生任何影响?
【问题讨论】:
-
您实际在哪里访问数据?严格的别名仅适用于取消引用指针时。
-
@Lundin
ArenaAlloc的使用与 malloc 非常相似。例如:int *a = ArenaAlloc(&arena, sizeof(*a)); *a = 1000;. -
这本身并不是一个严格的别名问题。仅当您以 uint8_t 访问它,然后以 int 访问它时,问题才会出现。
-
@Lundin 这仅适用于 malloc 的内存,对吧?如果我有一个 uint8_t 局部变量,那么当它作为 int 访问时,即使我以前实际上没有访问它,它也会违反?如果您可以访问具有不同类型的 malloc 内存的不同部分,编译器会跟踪与之相关的偏移量和有效类型?
-
@WingerSendon:有效类型规则是 C99 中最糟糕的部分,据我所知,除了制造混乱和不和谐外,没有任何用处。每一种可能的解释要么产生不可行的极端情况,要么要求编译器放弃规则旨在促进的许多优化,要么两者兼而有之。
标签: c strict-aliasing flexible-array-member