以下结构X
有3个字节的有效负载和1个字节的填充:
struct X
{
short a;
char b;
};
memory layout: aab.
以下结构Y
有4个字节的有效负载和2个字节的填充:
struct Y
{
X x;
char c;
};
memory layout: aab.c.
有没有办法让X
嵌套在Y
内并拥有sizeof(X) == 4 && sizeof(Y) == 4
?
memory layout: aabc
理想情况下,我希望对所有类型X
进行此类空间优化(将X
视为模板参数)。
答案 0 :(得分:1)
这是一个编译器设置。在某些情况下,填充是内存访问正常工作所必需的。在某些架构中,这是效率问题,在其他架构中,如果没有正确对齐,程序将崩溃。在这种情况下,您有16位对齐,直接在奇数地址上访问c
可能会导致麻烦。
但是,您可以使用pack
pragma(或编译器为其提供的任何其他选项)强制关闭对齐。
问题是为什么。如果依赖于此 - 您的程序可能无法在各种体系结构上移植且不可预测。
答案 1 :(得分:1)
如果您很幸运,并且与您的示例不同,X不是POD,那么推导可以提供帮助
struct X
{
X(){} // not POD
short a;
char b;
};
struct Y : X
{
char c;
};
Y的尺寸为4,x86_64上的钛金属ABI。
答案 2 :(得分:0)
您可以使用pragma强制对齐:
#pragma pack(push, 1)
struct X
{
short a;
char b;
};
#pragma pack(pop)
Microsoft的C ++编译器支持此功能。我不知道这是否是一种可移植的方式。
答案 3 :(得分:0)
在gcc
中,您可以使用__attribute__((packed))
关键字声明您的结构,以保持特定的字节对齐或填充。
例如,您可以执行类似
的操作typedef struct X
{
short a;
char b;
} __attribute__((packed)) X;
typedef struct Y
{
X x;
char c;
} __attribute__((packed)) Y;
现在sizeof(Y)
将是4个字节...唯一的问题是,为了满足硬件平台的字节对齐要求,您需要为任何需要完成的解包支付性能损失。< / p>
答案 4 :(得分:0)
是的,但它不是标准的C / C ++,需要特定于编译器的扩展。对于MSVC,请使用pack
pragma:
#pragma pack(push, 1)
struct X
{
...
};
#pragma pack(pop)
对于GCC,请使用packed
type attribute:
struct __atribute__((packed)) X
{
...
};
使用一些预处理器宏和__pragma
token,您可以在两个编译器中使定义工作,而不需要一堆#if
条件。
答案 5 :(得分:0)
由于明显的原因,X
和Y
的大小不能为4(如果可能的话,X
会有多个定义,正常填充的一个和一个填充由char
的{{1}}使用。所以Y
唯一的方法是4,如果Y
被更改以消除其填充。这可以通过编译器特定的编译指示或指令来完成。但是,由于这可能会导致X
未对齐访问,因此会有效地限制程序的可移植性(如果进行了未对齐的访问,某些体系结构甚至会崩溃)。
相反,你能更清楚地解释一下你希望在这里实现的最终结果吗?
答案 6 :(得分:0)
问题归结为:嵌套时如何将内部结构的 sizeof 进行包装,并进行 papped 进行正确对齐分配时?答:我不能,因为该语言无法提供声明,并且所有__attribute__s和#pragmas都无济于事。
最明显的解决方法是别名整个结构:
struct X
{
short a;
char b;
};
struct Y
{
short a;
char b;
char c;
};
但是,这样做的缺点是,每当要切片结构时,都需要进行显式转换:
X_taking_fct(*(struct X *)&Y_var);
从正面看,访问外部结构的成员很自然:
char_taking_fct(Y_var.c);
这种情况可以反过来:
struct X
{
short a;
char b;
};
union Y
{
struct X x;
struct {
short a;
char b;
char c;
} extra;
};
现在您可以执行以下操作:
X_taking_fct(Y_var.x);
以需要此为代价:
char_taking_fct(Y_var.extra.c);
输入C11匿名结构(gcc支持此结构的时间更长):
struct X
{
short a;
char b;
};
union Y
{
struct X x;
struct {
// the dummy_ prefix is not strictly necessary, but avoids confusion
short dummy_a;
char dummy_b;
char c;
};
};
现在可以同时访问内部和外部成员了:
X_taking_fct(Y_var.x);
char_taking_fct(Y_var.c);
但是,无法避免成员的多余声明。这显然很丑陋,并存在不同步的风险。通过将内部结构的主体放入宏中,至少可以避免这种风险:
#define X_body(pfx) \
short pfx##a; \
char pfx##b
struct X
{
X_body();
};
union Y
{
struct X x;
struct {
X_body(dummy_);
char c;
};
};