我正在尝试读取从网络接收的一系列比特(以预定义的格式),并且想知道我们是否必须照顾到联盟。
例如,预定义格式表示从最高位开始,收到的数据看起来像这样
|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)
答案 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)
这是UB。 data
指向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
并非便携式做事。
我建议在进行位操作之前使用函数将数据转换为本机类型。