[英]Why is the size of packed struct 5 instead of 4 bytes here?
參見在線示例: Ideone示例
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
為什么編譯器會將結構的大小報告為5個字節而不是4個? 它應該包含32位。
問題是__attribute__((packed))
不執行按位打包。 它只是保證struct
成員之間沒有填充。 您可以嘗試這個更簡單的示例,其中size也報告為5:
typedef struct structTag {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
按位打包僅適用於位域成員。 您需要將結構重新設計為結構與bitfields messageID / priority / canFlags的結合,以及帶有bitfields rowID / canFlags的結構。 換句話說,您需要有一些重復或使用訪問器宏或成員函數。
這是因為內存對齊:編譯器不會在一個字節的中間啟動canFlags
,它會在下一個字節的開頭(可能是*)啟動它。 因此,初始聯合有四個字節, canFlags
有一個字節。
例如,如果你將canFlags
移動到聯合中,那么它(可能是*)的大小為4:
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
uint32_t rawID : 29;
uint8_t canFlags : 3; /* <==== Moved */
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
有關ideone的更新示例 。 顯然,這種具體的變化可能不是你想要的; 我只是在證明問題是在字節邊界上開始一個新字段。
*“可能”因為最終取決於編譯器。
使用數據結構對齊在計算機存儲器中排列和訪問數據。 其中有兩個相關問題
當計算機執行寫操作時,它通常以4個字節的多個字節寫入(對於32位系統)。 這一行為的一個原因是提高績效的目標。 因此,當您編寫任何數據結構時,它具有前1個字節變量,然后是4個字節的可變數據,它將在第一個1字節數據之后執行填充,以在32位邊界上對齊它。
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
現在在上面的數據結構中你正在使用__attribute__ ((packed))
,這意味着沒有填充。 所以uint32_t是4個字節,但是你說它有26位和3位優先級。 現在,因為在一個結構中有兩個變量,所以它將保留32位而不是29位,這樣您的第一個結構的信息就會在邊界上進行分配。
現在對於canFlags它將需要另一個字節。 所以這使得5個字節而不是4個字節。
在某些編譯器中,要“合並”這些位,所有項必須是相同的類型。 所以把它uint32_t
你現在有uint8_t
- 這似乎不是編譯器中的情況IdeOne使用tho'
[無論如何,編譯器如何合並這些位仍然取決於它,因此絕對保證數據存儲為32位的唯一方法是使用單個uint32_t
並聲明一個執行相關移位的類。 anding / oring來操縱值 - 唯一的保證是你的struct中的ONE元素至少有你所要求的位數]
正如其他人所指出的那樣,除了字節邊界之外,你無法啟動新結構。 我通過在union中包含第二個結構來修復它,如下所示: http : //ideone.com/Mr1gjD
#include <stdint.h>
#include <stdio.h>
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
struct {
uint32_t rawID : 29;
uint8_t canFlags : 3;
};
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
int main() {
printf("size: %d", sizeof(idSpecial));
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.