C++ 字节内的Endianess

C++ 字节内的Endianess,c++,endianness,C++,Endianness,最近,我正在追踪一个错误,它出现在网络通信的双方有不同的终端时。一方已经发送了一份标记为最后一段的电报,而另一方仍在无休止地等待最后一段 我读了这段代码: #ifndef kBigEndian struct tTelegram { u8 lastSegment : 1; u8 reserved: 7; u8 data[1]; }; #else struct tTelegram { u8 reserve

最近,我正在追踪一个错误,它出现在网络通信的双方有不同的终端时。一方已经发送了一份标记为最后一段的电报,而另一方仍在无休止地等待最后一段

我读了这段代码:

#ifndef kBigEndian
    struct tTelegram
    {
       u8 lastSegment : 1;
       u8 reserved: 7;
       u8 data[1];
    };
#else
    struct tTelegram
    {
       u8 reserved: 7;
       u8 lastSegment : 1;
       u8 data[1];
    };
#endif
我知道endianness关注多字节类型,例如int、long等,但为什么在前面的代码中它会关注呢<代码>最后一段和
保留
位于单个字节内


这是一个bug吗?

结构中有16位。在32位或64位体系结构上,取决于尾数,
数据
可能位于保留的和
最后一段
之前,也可能在查看原始二进制文件时位于“之后”。如果我们考虑32位,您的结构可以沿着32位边界打包。可能是这样的:

 padbyte1 padbyte2 data lastSegment+reserved
或者看起来像这样

 lastSegment+reserved data padbyte1 padbyte2
因此,当您将这16位放在导线上,然后在另一侧重新解释它们时,您是否知道您是在获取
数据
还是
最后一段


您的问题不在字节内,它的
数据
位置与
保留
最后一段

有关。对于位字段,即使在同一CPU上运行的不同编译器之间,也无法保证排序。理论上,您甚至可以通过更改同一个编译器的标志来改变顺序(不过,公平地说,我必须补充一点,我从来没有见过这种情况发生)。

跨编译器和体系结构的位打包布局是不可移植的,是由实现定义的。你不能假设它会以同样的方式完成。另请参见:所以当通过网络将字节传递给另一端时,另一端不能保证得到正确的值?@EricZ:没错。或者更准确地说,实际上没有一个“正确的值”可以接收。另一方将获得发送的相同字节。。。但接收字节的程序的编译方式可能不同,因此它将结构的成员变量与发送字节的程序的不同位相关联,这将导致混淆/不兼容,即使发送方和接收方使用相同的源代码。如果您避免使用C的位字段功能,而是使用您自己的位打包逻辑(使用位移位和按位and和按位or)来打包/解包字节,您可以避免这种特殊的问题。但是通用网络协议是如何工作的呢?例如,它通常只强制执行网络字节顺序。但它如何保证另一方接收到与原始方完全相同的数据?您通过MSN向您的朋友发送了一条消息,例如,他可能会收到另一条消息?糊涂了。@EricZ:至少如果你通过TCP发送,你可以很好地保证在电线一端的东西会与另一端的东西相匹配。问题完全在于CPU如何编程来解释位。Jeremy是对的:避免这种情况的主要方法是自己管理位打包和解包。因此,我应该更改endianness ifdef的位置,以便在大端ian中
lastsgment+reserved
位于
data
之前,在小端ian中位于
data
之后。是吗?@EricZ:不,如果你想拥有一个定义良好的数据格式,就应该避免完全使用位字段。