我需要将位域结构从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; };
您可以使用32位整数,并使用and-和bitshift运算符从中提取信息。 有了这个,你可以简单地使用htonl(host-to-network,long)。 网络字节顺序是大端。
这不会像位字段那样优雅,但至少你会知道你拥有什么,而不必担心编译器填充你的结构。
处理器字节顺序与位字段排序无关。 在同一台计算机上使用两个编译器很可能使用相反的位域排序。 所以,鉴于此:
union { unsigned char x; struct { unsigned char b1 : 1; unsigned char b2 : 7; }; } abc; abc.x = 0; abc.b1 = 1; printf( "%02xn", 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__
适用于我们使用的编译器,因此您可能需要查看哪个适合您…
那里有两个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标准是否要求结构符合一个单词(尽管我希望大多数编译器都这样做)。
您希望在通道(文件或网络)和结构之间执行此操作。 我的首选做法是通过以已知表示forms构建文件缓冲区的写代码和匹配反转该转换的读取代码来隔离文件I / O与结构。
您的具体示例特别难以猜测,因为位域定义为unsigned int,而sizeof(unsigned int)
特别不可移植。
假设作为SWAG的sizeof(int)==4
然后获取指向结构的指针并重新编写单个字节可能会得到你想要的答案。
为不同平台定义结构的技巧可能有用,但是在示例中,您引用的是字节边界处没有干净的中断,因此不可能在不进行拆分的情况下在另一个平台上生成等效的一个平台一个或多个字段分成两部分。
交换字节应该足够了。 一个字节内的位位置在大端和小端都是相同的。
例如:
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];
当物理布局很重要时,不应使用位字段,因为它是实现定义的,填充较大的字的顺序。
为了实现这一目标,我终于得到了一个解决方案(一些从上面的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;
}
经过一些实验后,我发现这种方法只有在元素完全填满结构时才有效,即没有未使用的位。
需要了解更多c/c++开发分享在位域结构上转换Endianess,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享在位域结构上转换Endianess相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/936074.html