为什么这个结构体填充技巧有效?
Why does this struct padding trick work?
考虑这个简单的程序
#include <iostream>
struct A
{
int x1234;
short x56;
char x7;
};
struct B : A
{
char x8;
};
int main()
{
std::cout << sizeof(A) << ' ' << sizeof(B) << 'n';
return 0;
}
打印8 12
。尽管B
可以在不破坏对齐要求的情况下打包成8字节,但它却占用了贪婪的12字节。
有sizeof(B) == 8
会很好,但答案是结构体的大小是否需要是该结构体对齐的精确倍数?说明没有办法。
因此,当下面的
struct MakePackable
{
};
struct A : MakePackable
{
int x1234;
short x56;
char x7;
};
struct B : A
{
char x8;
};
打印8 8
。
这是怎么回事?我怀疑标准布局类型与此有关。如果是这样,那么当该特性的唯一目的是确保与C的二进制兼容性时,它导致上述行为的理由是什么?
编辑:正如其他人指出的那样,这是ABI或特定于编译器的,所以我应该补充说,使用以下编译器在x86_64-unknown-linux-gnu上观察到这种行为:
- 叮当声3.6
- gcc 5.1
我还注意到clang的struct dump中有一些奇怪的东西。如果我们要求没有尾部填充("dsize")的数据大小,
A B
first 8 9
second 7 8
,那么在第一个例子中我们得到dsize(A) == 8
。为什么不是7?
这是一个数据点,但不是一个完整的答案。
假设我们有(作为一个完整的翻译单元,而不是一个代码片段):
struct X {};
struct A
{
int x1234;
short x56;
char x7;
}
void func(A &dst, A const &src)
{
dst = src;
}
在g++中,这个函数被编译为:
movq (%rdx), %rax
movq %rax, (%rcx)
但是,如果使用struct A : X
,则此函数为:
movl (%rdx), %eax
movl %eax, (%rcx)
movzwl 4(%rdx), %eax
movw %ax, 4(%rcx)
movzbl 6(%rdx), %eax
movb %al, 6(%rcx)
这两种情况实际上对应的尺寸分别是OP例子中的8 12
和8 8
。
这样做的原因非常清楚:A
可能被用作某些类B
的基,然后调用func(b, a);
必须小心不要干扰b
的其他成员,这些成员可能位于填充区域(在OP的示例中为b.x8
);
我在c++标准中看不到A : X
的任何特殊属性,这将使g++决定填充在struct A : X
中可重用,但在struct A
中不可重用。A
和A : X
都是可复制的, 标准布局和POD。
我猜这一定是一个基于典型使用的优化决策。没有重用的版本复制起来会更快。也许一个g++ ABI设计人员可以评论一下?
有趣的是,这个例子表明,简单的可复制并不意味着memcpy(&b, &a, sizeof b)
等同于b = a
!
我不是一个真正的c++语言律师,但是我目前发现的是:
参考这个问题的答案,一个结构体只保留一个标准布局POD,而在它自己和它的父类中只有一个类具有非静态成员。所以在这个想法下,A
在两种情况下都有保证的布局,但B
在情况下都没有。
std::is_pod对A
为真,对B
为假。
- 第一例:http://ideone.com/jyPb5J
- 第二个案例:http://ideone.com/bYcLXa
所以,如果我自己正确地理解了这一点,编译器被允许在两种情况下用B
的布局做它想做的事情。显然,在第二种情况下,它感觉像是利用了A
的填充字节。
- 在c++中用vector填充一个简单的动态数组
- 欧拉项目#8答案是大以获得有效答案
- 如何使用用户输入在C++中正确填充2D数组
- 调整大小后指向元素值的指针unordered_map有效?
- 如何找到大小'x'数组是否完全填充,在C++?
- 为什么是0;C++中的有效语句
- 最高有效数字侧的第N位
- 填充红黑树的最有效方法是什么?
- 如何有效地填充稀疏矩阵
- 如何有效地用枚举填充 2D std::数组
- 更有效的填充unordered_set方式?
- 如何有效地用向量填充结构
- 在C++中,在图像周围填充黑色边框是最有效的方法
- Cuda有效地将数据插入到未排序的填充数组中
- 如何普遍有效地填充缓冲液?(传递插入迭代器?器皿?等)
- 在代码中的同一位置最有效地填充静态标题列表和动态值列表
- 用QPixmap填充QWidget的有效方法
- 我如何使我的洪水填充算法更有效
- 为什么这个结构体填充技巧有效?
- 用向量来填充向量的有效方法是什么?