C 从无符号字符中读取N位时,endianess是否重要

C 从无符号字符中读取N位时,endianess是否重要,c,endianness,C,Endianness,我试图读取从网络接收到的一系列比特(以预定义的格式),我想知道我们是否需要处理endianees 例如,预定义格式表示从最重要的位开始接收的数据如下所示 |R|| 11 bits data||20 bits data||16 bits data| where R is reserved and ignored. 我的问题是,在提取时,我是否必须处理Endianness,或者我可以这样做 u16 first_11_bits = *(u16 *)data & 0x7FF0) >&

我试图读取从网络接收到的一系列比特(以预定义的格式),我想知道我们是否需要处理endianees

例如,预定义格式表示从最重要的位开始接收的数据如下所示

 |R||  11 bits data||20 bits data||16 bits data| where R is reserved and ignored.
我的问题是,在提取时,我是否必须处理Endianness,或者我可以这样做

u16 first_11_bits = *(u16 *)data & 0x7FF0) >>4
u32 20_bits_data  = *(u32 *)data & 0x000FFFFF)
这是。
data
指向一个
u16
,或者它指向一个
u32
。不能两者都指。这不是endianess问题,只是访问无效。您必须通过为写入而访问的指针类型进行读取。不管你用哪种方式写,你都是这样读的。然后,您可以对读回的值执行位操作,该值将与您写入的值相同

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

例如:

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

编译器可以自由地将最后一行视为
u16 j=i。它最后一次以同样的方式读取
i
,并且可以自由地假设对
u32*
的写入不会影响从
u16*
读取的结果。是的,在读取/写入外部资源(文件、网络等)时,您将始终需要担心endianness。但它与位操作无关

直接转换
(u16*)数据
不是一种可移植的方式


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

什么样的网络?IP是以字节为单位定义的,因此,无论比特流在底层中的顺序是什么,它都已从您那里抽象出来,您将按照CPU理解的顺序接收比特。这意味着C为访问这些位提供的抽象是可移植的。考虑在C中向左或向右移位。无论CPU中的endianness是什么,C中移位的方向和语义都不会改变


所以问题是:数据是如何被另一端编码成字节流的?然而,另一端编码的数据应该是您解码它的方式。如果他们只是把位塞进一个字节,然后通过网络发送那个字节,那么你就不必在意了。若他们将位放入一个int16中,然后按网络字节顺序发送,那个么你们需要担心那个int16的尾数。如果他们将位放入一个int32并发送,那么您需要担心该int32的endianness

您需要使用
&
进行掩蔽,而不是
&
。那些
&
可能不会做您认为会做的事情。它们是“逻辑and”运算符,而不是按位and(“
&
”),我会说是的。如果你从小端机发送一个数字,然后在大端机上接收,反之亦然。通常发送的数据应该是大端格式的,我们需要更多的上下文。
数据是如何到达的?它看起来像是
uint8_t data[MAX_LEN];read(fd,data,sizeof(data);
?嗨,大卫,我不确定我是否明白。“不管你用什么方式写的,你都是这样读的。”我不知道它是怎么写的。比特流是我通过空中接收的,我必须以预定义的格式对比特流进行解码。接收的比特总是字节对齐的。我可以做以下操作:u32 first_32_bits=(u32)data;first_11_bits=(first_32_bits&0x7FF0)>>4、 20位\u data=first\u 32位&0x000FFFFFIt取决于您是如何编写的。如果您是以
u32
的形式编写的,则必须以这种方式读取。如果不是,则不能。
u16 i = * (u16 *) data;
* (u32 *) data = 0;
u16 j = * (u16 *) data;