当 A 和 B "the same"时断言(sizeof(A) == sizeof(B))是否安全?

Is it safe to assert(sizeof(A) == sizeof(B)) when A and B are "the same"?

本文关键字:sizeof 是否 安全 the same 断言      更新时间:2023-10-16

假设我有两个我期望具有完全相同的内存布局的类:

struct A {
    int x;
    int y;
};
/* possibly more code */
struct B {
    int a;
    int b;
};

标准中是否有任何保证我可以安全的static_assert(sizeof(A) == sizeof(B))

作为较弱的变体考虑

struct C {
    int a;
};
static_assert( sizeof(A) >= sizeof(C) );   // can this ever fail?
static_assert( sizeof(A) >  sizeof(C) );   // can this ever fail?

这个问题是由这个问题触发的。天真的我不会指望任何断言会失败,但是这可以保证吗?

a 人为反面示例:

#include <stdint.h>
struct A {
    int32_t a;
    int64_t b;
};
#pragma pack(4)
struct B {
    int32_t a;
    int64_t b;
};
static_assert(sizeof(A) == sizeof(B));

g++在64位Linux中汇编的收益:

a.cc:15:1: error: static assertion failed
static_assert(sizeof(A) == sizeof(B));

标准中的任何内容都禁止实现一个实现,该实现识别所有被用作工会部分的结构,并在未使用的任何结构的每个元素之后添加了随机量的填充物以这种方式。另一方面,如果实现可以处理的标签数量,也不会禁止实现实现,那么任何事情都不会禁止实施实现实现。

所有这些事情都属于标准允许实施的事物类别,但是即使标准允许,通常也应该期望哪些质量实施避免执行。该标准没有努力禁止实施愚蠢的事情,也没有猜测某些专业实施是否有充分的理由以非典型方式处理某些东西。相反,它预计编译器作家将尝试满足客户的需求,无论标准是否要求他们这样做。

是的,标准可以保证可以安全地断言。这里的相关术语是布局兼容

标准定义了两个部分。首先,它定义了数据构件的常见初始序列是(但仅用于标准layout structs ):它是两个构造之间等效的数据构件的序列。该标准包括一个示例,但我将使用略有不同的示例来避免一些技术:

struct A { int a; char b; };
struct B { int b1; char b2; };
struct C { int x; int y; };

在该示例中,AB的常见初始布局都是其成员,而对于AC,它只是他们的第一个成员。然后,如果共同的初始布局仅仅是整个类别,则将结构定义为布局兼容

如果您有两种不同的布局兼容类型的实例,例如上述示例中的AB,则 *可以 *假设它们具有相同的大小:

static_assert(sizeof(A) == sizeof(B));

但是,您 *不能 *(理论上)在不调用未定义的行为的情况下(从理论上)施放,因为这违反了混杂规则:

A a{1, 'a'};
B* b = reinterpret_cast<B*>(&a); // undefined behaviour!
do_something_with(b);

您可以做什么,遵守通常的const/volatile规则以及有关数据成员微不足道的规则(请参阅允许允许使用C 11中的类型?),是否使用memcpy在与布局兼容的结构。当然,正如当前的最高答案所暗示的那样,在成员之间进行填充可能是随机的。

A a{1, 'a'};
B b;
memcpy(&b, &a, sizeof(b)); // copy from a to b
do_something_with(b);

如果do_something_with通过参考来进行参数并修改其参数,那么您将需要从b复制到a,以反映那里的效果。实际上,通常会优化这是您期望上述演员的事情。

Atomsymbol的答案给出了一个示例,似乎与上述所有内容相矛盾。但是您询问了标准中的内容,而影响填充的#pragma超出了标准覆盖的内容。

您断言的唯一实例是在包装标准有区别时。否则断言必须为真。

编译器仅具有结构定义以验证成员的偏移,因此,除非Layoùt保持一致,否则您将无法访问结构。