簡體   English   中英

在位域結構上轉換Endianess(再次)

[英]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             ]

從這里我看不出如何重新排序abcd以在小端和大端機器上形成相同的位模式。 原因是結構的成員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.

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