在位域结构上转换Endianess

foo*_*foo 7 c endianness data-structures

我需要将位域结构从little-endian转换为big-endia架构.如果我只是交换结构元素,那么在字节边界中会出现问题的最佳方法是什么?

Ex结构是:

struct {
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
}; 
Run Code Online (Sandbox Code Playgroud)

fal*_*tro 8

您可以使用32位整数,并使用and-和bitshift运算符从中提取信息.有了这个,你可以简单地使用htonl(host-to-network,long).网络字节顺序是大端.

这不会像位字段那样优雅,但至少你会知道你拥有什么,而不必担心编译器填充你的结构.


小智 6

处理器字节顺序与位字段排序无关.在同一台计算机上使用两个编译器很可能使用相反的位域排序.所以,鉴于此:

union {
    unsigned char x;
    struct {
        unsigned char b1 : 1;
        unsigned char b2 : 7;
    };
} abc;
abc.x = 0;
abc.b1 = 1;
printf( "%02x\n", abc.x );
Run Code Online (Sandbox Code Playgroud)

除非您碰巧有详细的文档,否则了解是否打印出01或80的唯一方法就是尝试它.


epa*_*tel 5

在将代码从MIPS移植到Linux/x86的项目中,我们确实喜欢这样.

struct {

#ifdef __ONE_ENDIANESS__
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
#define _STRUCT_FILLED
#endif /* __ONE_ENDIANESS__ */

#ifdef __OTHER_ENDIANESS__
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
#define _STRUCT_FILLED
#endif /* __OTHER_ENDIANESS__ */

};

#ifndef _STRUCT_FILLED
#  error Endianess uncertain for struct
#else
#  undef _STRUCT_FILLED
#endif /* _STRUCT_FILLED */
Run Code Online (Sandbox Code Playgroud)

__ONE_ENDIANESS____OTHER_ENDIANESS__是适合我们使用,所以你可能需要考虑其是否适合你的编译器...


foo*_*foo -3

为了实现这一点,我终于得到了一个解决方案(一些来自上面 epatel 的解决方案)。这是我从 x86 转换到 Solaris SPARC 的情况。

我们需要首先交换传入的结构,然后以相反的顺序读取元素。基本上在查看了结构如何对齐之后,我发现字节序和位序的字节顺序都发生了变化。这是一个伪代码。

struct orig
{    
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
};

struct temp
{    
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
}temp;


func (struct orig *toconvert)
{
    struct temp temp_val;
    //Swap the bytes
    swap32byte((u32*)toconvert);
    //Now read the structure in reverse order - bytes have been swapped
    (u32*)&temp_val = (u32 *)toconvert;
    //Write it back to orignal structure
    toconvert->b6=temp_val.b6;
    toconvert->b5=temp_val.b5;
    toconvert->b4=temp_val.b4;
    toconvert->b3=temp_val.b3;
    toconvert->b2=temp_val.b2;
    toconvert->b1=temp_val.b1;
Run Code Online (Sandbox Code Playgroud)

}

经过一些实验,我发现这种方法仅在元素完全填充结构时才有效,即没有未使用的位。