gpt4 book ai didi

c - 打包的相同结构是否保证具有相同的内存布局?

转载 作者:行者123 更新时间:2023-12-05 08:24:45 27 4
gpt4 key购买 nike

假设我有两个结构:objectwidget:

struct object {
int field;
void *pointer;
};
struct widget {
int field;
void *pointer;
};

还有一个函数:

void consume(struct object *obj)
{
printf("(%i, %p)\n", obj->field, obj->pointer);
}

我知道如果我尝试这样做:

struct widget wgt = {3, NULL};
consume(&wgt);

我会违反 strict aliasing rule ,因此具有未定义的行为。

据我所知,未定义的行为是由于编译器可能以不同方式对齐结构字段:也就是说,填充字段以与地址边界对齐(但从不更改字段顺序,因为顺序保证是遵守标准)。

但是如果这两个结构是 packed 呢? ?他们会有相同的内存布局吗?或者,换句话说,上面的 consume() 是否仍然有未定义的行为(尽管有持续的编译器警告)?

注意:我使用 struct __attribute__((__packed__)) object { ... }; 进行打包 (GCC)。

最佳答案

它们很可能具有相同的布局;这将成为编译器 ABI 的一部分。

相关的架构和/或操作系统可能有一个标准的 ABI,它可能包含也可能不包含 packed 的规范。但是编译器将有自己的 ABI 以可预测的方式布置它们,尽管算法可能不会在编译器源代码以外的任何地方精确地写下来。

但是,这并不意味着您的代码是安全的。严格的别名规则适用于指向不同类型的指针,无论它们是否具有相同的布局。

这是一个可以用gcc -O2编译的例子:

#include <stdio.h>

__attribute__((packed))
struct object {
int field;
void *pointer;
};

__attribute__((packed))
struct widget {
int field;
void *pointer;
};

struct widget *some_widget;

__attribute__((noipa)) // prevent inlining which hides the bug
void consume(struct object *obj)
{
some_widget->field = 42;
int val = obj->field;
printf("%i\n", val);
}

int main(void) {
struct widget wgt = {3, NULL};
some_widget = &wgt;
consume((struct object *)&wgt);
}

Try on godbolt

您可能希望此代码打印 42,因为 some_widgetobj 都指向 wgt 并且因此 val = obj->field 应该读取由 some_widget->field = 42 编写的相同的 int。但实际上它打印了 3。允许编译器假定 objsome_widget 没有别名,因为它们具有不同的类型;所以写和读被认为是独立的,可以重新排序。

在标准层面上,您正在通过左值*some_widget 访问对象wgt,其有效类型为struct widget其类型为 struct object。这些类型不兼容,因为它们具有不同的标签(widget vs object),因此行为未定义。

关于c - 打包的相同结构是否保证具有相同的内存布局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73140420/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com