题
我需要一个位字段结构由小端转换为大endia架构。 什么是做到这一点的最好方式,因为会在字节边界的问题,如果我只是交换结构元素。
实施例的结构是:
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;
};
解决方案 8
要获取这是怎么回事,我终于得到了一个解决方案(有些什么从epatel的解决方案上面的推导)。这是,如果我从86转换为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;
}
在一些尝试我发现,这种方法才有效,如果元件完全填充结构,即没有未使用的比特。
其他提示
您可以使用一个32位整数,并提取出信息使用和 - 和位移操作符提升它的。与在的地方,你可以简单地使用htonl(主机到网络长)。网络字节顺序是大端。
这不会是一个位字段优雅,但至少你会知道你有什么,也不会担心编译器填充您的结构。
处理器字节序是无关的位字段排序。这是完全有可能在同一台计算机上使用两种编译器订货相反对于位域。因此,鉴于这样的:
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 );
除非你碰巧有详细的文档,要知道这是否会打印出01或80的唯一方法是尝试一下。
在从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 */
在宏__ONE_ENDIANESS__
和__OTHER_ENDIANESS__
是适合我们使用,所以你可能需要考虑这对你来说是合适的编译器...
您有有2层16位的部分(前三个字段和最后三个字段是16位)。
这只是65536条目。因此,有保存字段的位反转的版本的查找表。包裹结构与它有两个16位字段的另一个结构工会使它更容易些?
喜欢的东西(未测试的,我不靠近C编译器):
union u {
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;
} bits;
struct {
uint16 first;
uint16 second;
} words
} ;
unit16 lookup[65536];
/* swap architectures */
void swapbits ( union u *p)
{
p->words.first = lookup[p->words.first];
p->words.second = lookup[p->words.second];
}
查找表的人口留给读者作为练习读者:)
然而,仔细阅读你的编译器的文档。我不知道如果C标准要求结构,以适应一个字(尽管我希望大多数编译器来做到这一点)。
您想通道(文件或网络)和您的结构之间做到这一点。我的优选的实践是分离的文件I / O从通过建立在已知的表示该文件缓冲器写入代码结构和匹配读取反转该变换代码。
您具体的例子是特别困难的,因为在该位字段被定义为无符号的int和sizeof(unsigned int)
特别非便携式去猜测。
假设作为赃物那么sizeof(int)==4
得到一个指针结构,可能reording个人字节让你你想要的答案。
不同定义结构针对不同平台的诀窍的可能的工作,但在这个例子中,你举没有在字节边界划清界限,所以它不可能是可能产生在另一个平台的不分割的字段的一个或多个成两个部分的等效。
它应该是足够交换字节。一个字节中位位置是在大,小尾数相同。结果 例如:
char* dest = (char*)&yourstruct;
unsigned int orig = yourstruct;
char* origbytes = (char*)&orig;
dest[0] = origbytes[3];
dest[1] = origbytes[2];
dest[2] = origbytes[1];
dest[3] = origbytes[0];
您不应该使用位字段时的物理布局是很重要的,因为它是实现定义在何种顺序较大字填充。