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