簡體   English   中英

避免C中的結構填充

[英]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 ),以及最后對齊要求不那么嚴格的那些( shortchar ) 。 如果組件的總長度加起來(例如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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM