简体   繁体   English

在位域结构上转换Endianess(再次)

[英]Converting Endianess on a bit field structure (again)

This question was asked before, but I'm still a bit confused on how to deal with bitfield structures when moving to a platform with the opposite endianness (big to little in this case). 之前曾问过这个问题,但是当我转向具有相反字节序的平台时,我仍然对如何处理位域结构感到困惑(在这种情况下,从大到小)。 So if I have this: 所以,如果我有这个:

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;

Is the correct way to deal with this, like this? 处理这个问题的正确方法是这样的吗?

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;

Or something else? 或者是其他东西?

That's what I did, but it's not giving results I was expecting. 这就是我所做的,但它没有给出我期待的结果。 However there are other issues with this code, so I'm not sure if the above was actually wrong or not. 但是这个代码还有其他问题,所以我不确定上面是否真的错了。 Hoping to get insight here so I can knock this part off the list. 希望能在这里获得洞察,这样我就可以将这部分从列表中删除。

In fact I need to have the code work on both platforms still, so I'd be wrapping things around #defines, but I didn't want to clutter things here. 事实上,我需要让代码在两个平台上都能正常工作,所以我要把它们包装在#defines周围,但我不想在这里混乱。

我会保留你原来的内容,但在引用之前反转word的字节顺序(如果需要)。

You have more to worry about than endianess issues here. 你有更多的担心,而不是在这里的endianess问题。 Be aware that the details of how bitfields are laid out in memory is not defined by the C standard, meaning that two compilers can generate different results, even if they are targeting platforms with the same endianess. 请注意,C标准并未定义如何在内存中布置位域的详细信息,这意味着两个编译器可以生成不同的结果,即使它们是针对具有相同endianess的平台。 Some may treat the first bitfield listed as the lowest-address bit, and others may treat it as the highest-address bit. 有些可能会将列出的第一个位字段视为最低地址位,而其他位可能会将其视为最高地址位。

You have two options for resolving this. 您有两种方法可以解决此问题。

The first is with a healthy dose of #ifdef : 第一种是健康剂量的#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;

This leads to a messy structure definition, but allows the rest of the code to stay clean. 这导致了凌乱的结构定义,但允许其余代码保持干净。 Since you have fields that cross the byte boundary, you'll have to essentially come up with a new structure definition (possibly by trial and error) for every target architecture/platform. 由于您具有跨越字节边界的字段,因此您必须为每个目标体系结构/平台提供新的结构定义(可能通过反复试验)。 If you have to support multiple compilers that order bitfields differently for the same platform, then your definition will become even more complex. 如果您必须支持多个编译器,这些编译器对同一平台的位域命名方式不同,那么您的定义将变得更加复杂。

The other option is to avoid bitfields altogether and use bitmasks instead: 另一种选择是完全避免使用位域并改为使用位掩码:

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))

This requires the use of getter/setter methods, but you avoid most of the portability problems since you're explicitly specifying both the bit and byte orders for everything. 这需要使用getter / setter方法,但是您可以避免大多数可移植性问题,因为您明确指定了所有内容的位和字节顺序。

I'd say the following structure is not portable in terms of not changing the bit pattern used by the structure in memory from little to big endian or verse vica: 我说以下结构不可移植,不会改变内存中结构使用的位模式,从小端到大端或者维也纳:

typedef struct
{
    unsigned short a :5;
    unsigned short b :1;
    unsigned short c :5;
    unsigned short d :5;
} protocol_type;

Proof: 证明:

Big endian memory layout: 大端内存布局:

 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            ]

Little endian memory layout: 小端内存布局:

 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             ]

From this I see no way how to re-order a , b , c , and d to form the same bit pattern on either little and big endian machines. 从这里我看不出如何重新排序abcd以在小端和大端机器上形成相同的位模式。 The reason for this is the fact that the structure's member c crosses the byte boundary. 原因是结构的成员c穿过字节边界。


The following structure might be made portable: 以下结构可以是便携式的:

typedef struct
{
    unsigned short e :5;
    unsigned short f :3;
    unsigned short g :3;
    unsigned short h :5;
} protocol_type;

To keep the bit pattern in memory when switching endianess just mod it like so: 在切换endianess时保持位模式在内存中只需修改它就像这样:

typedef struct
{
    unsigned short g :3;
    unsigned short h :5;
    unsigned short e :5;
    unsigned short f :3;
} protocol_type;

A possible solution to the OP's problem would be to mod the structure the following way: 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