从unsigned char读取N位时,endianess是否重要

时间:2013-09-30 12:16:26

标签: c endianness

我正在尝试读取从网络接收的一系列比特(以预定义的格式),并且想知道我们是否必须照顾到联盟。

例如,预定义格式表示从最高位开始,收到的数据看起来像这样

 |R||  11 bits data||20 bits data||16 bits data| where R is reserved and ignored.

我的问题是在提取时我必须处理结束,或者我可以做什么

u16 first_11_bits = *(u16 *)data & 0x7FF0) >>4
u32 20_bits_data  = *(u32 *)data & 0x000FFFFF)

3 个答案:

答案 0 :(得分:1)

什么样的网络? IP是按字节数定义的,因此位流在底层中发生的顺序已被抽象出来,并且您按照CPU理解它们的顺序接收这些位。这意味着C为您提供访问这些位的抽象是可移植的。考虑在C中向左或向右移动。无论CPU中的字节顺序如何,C中移位的方向和语义都不会改变。

所以问题是:如何将数据编码到另一端的字节流中?然而,另一端编码数据应该是你解码它的方式。如果他们只是将位推入一个字节并通过网络发送该字节,那么您就不需要关心。如果他们将位放入一个int16然后以网络字节顺序发送它,那么你需要担心int16的字节顺序。如果他们将这些位放入int32并发送它,那么你需要担心int32的字节顺序。

答案 1 :(得分:0)

u16 first_11_bits = *(u16 *)data & 0x7FF0) >>4
u32 20_bits_data  = *(u32 *)data & 0x000FFFFF)

这是UBdata指向u16或指向u32。它不能指向两者。这不是一个endianess问题,它只是一个无效的访问。您必须通过访问写入的相同指针类型访问读取。无论你怎么写它,你就是这样读的。然后,您可以对读回的值执行位操作,这与您编写的值相同。

这可能出错的一种方法是编译器可以自由地假设通过u32 *的写入不会影响通过u16 *读取的值。因此写入可以是存储器,但是读取可以来自寄存器中缓存的值。这破坏了现实世界的代码。

例如:

u16 i = * (u16 *) data;
* (u32 *) data = 0;
u16 j = * (u16 *) data;

编译器可以将最后一行视为u16 j = i;。它以同样的方式读取i,可以自由地假设对u32 *的写入不会影响u16 *的读取结果。

答案 2 :(得分:0)

是的,在读取/写入外部资源(文件,网络......)时,您总是需要担心字节顺序。但它与位操作无关。

直接投射(u16 *)data并非便携式做事。

我建议在进行位操作之前使用函数将数据转换为本机类型。