在C ++中考虑这段代码
struct Base
{
std::int64_t x;
std::int64_t y;
};
static_assert(sizeof(Base) == 16, "Base not of size 16!");
struct Derived : Base
{
std::int32_t z;
}__attribute__((packed));
static_assert(sizeof(Derived) == 20, "Derived not of size 20!");
clang认为此代码有效,而gcc导致第二个static_assert触发。 ("派生的不是20号!)。如果我也添加在Base中打包的属性,那么在两个编译器中都可以。有谁知道哪一个是对的,为什么?
答案 0 :(得分:3)
两者都是对的。
允许编译器向您的类添加填充(在成员之间和结尾之间),并且它是否实现已定义,因此您的static_assert
基本上是测试依赖的东西在使用的编译器(和平台)上 - 因此它们不可移植,你无法在任何地方期望相同的结果。
您对__attribute__((packed))
的使用基本上告诉了解该属性的编译器,您希望获得特定行为而不是默认行为。在这种情况下,这可能会生成您想要的结果,但它也会产生影响(内存布局/使用以及某些CPU的性能)。你仍然无法确定所有编译器都会这样做。
答案 1 :(得分:1)
这是一个实现定义的概念,它在实现和编译器之间有所不同。
如上所述,允许编译器为类添加额外的空间,并且像您编写的代码不可移植。添加的空间量或填充量因编译器而异,并且没有代码可以具有满足所有内容的可靠检查。这会在不同的地方产生不同的结果,因为所有的编译器都不同。