[英]Converting Endianess on a bit field structure (again)
之前曾問過這個問題,但是當我轉向具有相反字節序的平台時,我仍然對如何處理位域結構感到困惑(在這種情況下,從大到小)。 所以,如果我有這個:
typedef struct
{
unsigned short a :5;
unsigned short b :1;
unsigned short c :5;
unsigned short d :5;
} protocol_type;
typedef union
{
protocol_type cmd;
unsigned short word;
}protocol_cmd_type;
處理這個問題的正確方法是這樣的嗎?
typedef struct
{
unsigned short d :5;
unsigned short c :5;
unsigned short b :1;
unsigned short a :5;
} protocol_type;
typedef union
{
protocol_type cmd;
unsigned short word;
}protocol_cmd_type;
或者是其他東西?
這就是我所做的,但它沒有給出我期待的結果。 但是這個代碼還有其他問題,所以我不確定上面是否真的錯了。 希望能在這里獲得洞察,這樣我就可以將這部分從列表中刪除。
事實上,我需要讓代碼在兩個平台上都能正常工作,所以我要把它們包裝在#defines周圍,但我不想在這里混亂。
我會保留你原來的內容,但在引用之前反轉word
的字節順序(如果需要)。
你有更多的擔心,而不是在這里的endianess問題。 請注意,C標准並未定義如何在內存中布置位域的詳細信息,這意味着兩個編譯器可以生成不同的結果,即使它們是針對具有相同endianess的平台。 有些可能會將列出的第一個位字段視為最低地址位,而其他位可能會將其視為最高地址位。
您有兩種方法可以解決此問題。
第一種是健康劑量的#ifdef
:
typedef struct
{
#ifdef CPU_IS_BIG_ENDIAN
unsigned short a :5;
unsigned short b :1;
unsigned short c :5;
unsigned short d :5;
#else
unsigned short d :5;
unsigned short c :5;
unsigned short b :1;
unsigned short a :5;
#endif
} protocol_type;
這導致了凌亂的結構定義,但允許其余代碼保持干凈。 由於您具有跨越字節邊界的字段,因此您必須為每個目標體系結構/平台提供新的結構定義(可能通過反復試驗)。 如果您必須支持多個編譯器,這些編譯器對同一平台的位域命名方式不同,那么您的定義將變得更加復雜。
另一種選擇是完全避免使用位域並改為使用位掩碼:
typedef unsigned char protocol_type[2];
#define extract_a(x) ((x[0] & 0xF8) >> 3)
#define extract_b(x) ((x[0] & 0x04) >> 2)
#define extract_c(x) (((x[0] & 0x03) << 3) | ((x[1] & 0xE0) >> 5))
#define extract_d(x) ((x[1] & 0x1F))
這需要使用getter / setter方法,但是您可以避免大多數可移植性問題,因為您明確指定了所有內容的位和字節順序。
我說以下結構不可移植,不會改變內存中結構使用的位模式,從小端到大端或者維也納:
typedef struct
{
unsigned short a :5;
unsigned short b :1;
unsigned short c :5;
unsigned short d :5;
} protocol_type;
證明:
大端內存布局:
d4 d3 d2 d1 d0 c4 c3 c2 c1 c0 b0 a4 a3 a2 a1 a0
<- byte 1 -> <- byte 0 ->
MSB LSB MSB LSB
[ address 1 ] [ address 0 ]
小端內存布局:
c1 c0 b0 a4 a3 a2 a1 a0 d4 d3 d2 d1 d0 c4 c3 c2
<- byte 0 -> <- byte 1 ->
MSB LSB MSB LSB
[ address 1 ] [ address 0 ]
從這里我看不出如何重新排序a
, b
, c
和d
以在小端和大端機器上形成相同的位模式。 原因是結構的成員c
穿過字節邊界。
以下結構可以是便攜式的:
typedef struct
{
unsigned short e :5;
unsigned short f :3;
unsigned short g :3;
unsigned short h :5;
} protocol_type;
在切換endianess時保持位模式在內存中只需修改它就像這樣:
typedef struct
{
unsigned short g :3;
unsigned short h :5;
unsigned short e :5;
unsigned short f :3;
} protocol_type;
OP問題的一個可能解決方案是通過以下方式修改結構:
typedef struct
{
#if defined(BIGENDIAN)
unsigned short a :5;
unsigned short b :1;
unsigned short c0 :2;
unsigned short c1 :3;
unsigned short d :5;
#elif defined(LITTLEENDIAN)
unsigned short c1 :3;
unsigned short d :5;
unsigned short a :5;
unsigned short b :1;
unsigned short c0 :2;
#else
#error "endianess not supported"
#endif
} protocol_type;
#define pt_c(pt) (pt.c0 & (pt.c1 << 2))
foo(void)
{
protocol_type pt;
... /* some assignment to pt ... */
/* to then access the original value of member c use the macro */
unsigned short c = pt_c(pt);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.