[英]Avoiding structure padding in c using __attribute__((packed))
[英]Avoiding Structure Padding in C
除了使用pragma pack aur位域之外,我們如何避免C中的結構填充? 還有其他方法嗎?
在結構的開頭包裝最大的物品。 最后包裝較小的物品。
struct optimal_packing
{
double d;
int i[4];
short j[3];
char s[24];
};
為了更准確一點,它是最需要最嚴格的對齊要求的項目(它們往往是指針和double
或者可能是long double
),以及最后對齊要求不那么嚴格的那些( short
和char
) 。 如果組件的總長度加起來(例如35個字節),您仍然可以最終得到尾部填充,但其中一種類型需要8字節對齊; 有5個字節的填充。
避免結構填充的唯一完全可移植且可靠的方法是根本不使用struct
中的真實成員。 使用單個char
數組成員,並定義訪問其內容的宏:
struct paddingless {
// char *p;
// double d;
// char c;
#define OFFSET_P 0
#define OFFSET_D (OFFSET_P + sizeof(char *))
#define OFFSET_C (OFFSET_D + sizeof(double))
#define OFFSET_END (OFFSET_C + sizeof(char))
char data[OFFSET_END];
};
便攜式getter和setter看起來像這樣:
inline double paddingless_get_d(const struct paddingless *o) {
double val;
memcpy(&val, o->data + OFFSET_D, sizeof(val));
return val;
}
inline void paddingless_set_d(struct paddingless *o, double val) {
memcpy(o->data + OFFSET_D, &val, sizeof(val));
}
如果您知道您的體系結構接受了未對齊訪問,那么您可以使用強制轉換來定義一個setter:
#define paddingless_get_d(o) (*(double *) ((o)->data + OFFSET_D))
#define paddingless_set_d(o, val) (*(double *) ((o)->data + OFFSET_D) = (val))
這是不可移植的,但可能比替代方案更快。 它適用於
vax
x86 ......
有一些事情需要考慮。 首先,編譯器添加填充是有原因的:它試圖為其指定的平台制作最佳的工作機器代碼。 所以通常填充是一件好事。 除了您要定義數據通信協議,硬件寄存器映射等的情況,其中字節數必須與特定規范匹配。
實際上沒有標准的方法可以避免填充。 如果結構大小與其所有單個成員的總和不匹配,則可以實現的最佳結果是編譯時斷言給出錯誤。 當斷言失敗時,您可以將編譯器設置更改為阻止填充。 較好的是:
static_assert(sizeof(mystruct) == (sizeof(mystruct.x) + sizeof(mystruct.y) +...));
如果你的C編譯器中沒有static_assert(你需要一個符合C11的版本),那么使用一些“ct_assert”宏,你可以在這個網站上找到很多。
但是,這不能以可移植的方式解決問題,您將依賴於編譯器設置。 唯一真正可移植的解決問題的方法是這樣的:
void mystruct_copy_from (uint8_t* raw_data, const mystruct_t* ms)
{
memcpy(raw_data, &ms->x, sizeof(ms->x));
raw_data += sizeof(ms->x);
memcpy(raw_data, &ms->y, sizeof(ms->y));
raw_data += sizeof(ms->y);
// ... and so on
}
uint8_t protocol [EXPECTED_STRUCT_SIZE];
mystruct_copy_from (protocol, &mystruct);
send(protocol); // some data communication interface without padding
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.