为啥 to_be_bytes() 和 to_le_bytes() 与我在这里期望的相反?

Posted

技术标签:

【中文标题】为啥 to_be_bytes() 和 to_le_bytes() 与我在这里期望的相反?【英文标题】:Why does to_be_bytes() and to_le_bytes() do the opposite of what I expect here?为什么 to_be_bytes() 和 to_le_bytes() 与我在这里期望的相反? 【发布时间】:2021-04-16 18:49:09 【问题描述】:

也许问题应该是“为什么我希望 to_be_bytes() 和 to_le_bytes() 在这里做相反的事情?”,但无论如何,情况如下:

fn main() 
    let buf: [u8; 2048] // Buffer I use to receive UDP messages

    let (_, entry, _) = unsafe  buf[14..].align_to::<u16>() ;
    // In memory entry looks like: 00 44 16 15   21 04 03 5a   03 67 03 6a   03 64 88 91

    let [first, second] = entry[0].to_be_bytes();
    
    assert_eq!(first, 0x44);
    assert_eq!(second, 0x00);

不应该是相反的吗?大字节序不是像在内存中保留顺序一样吗?​​

【问题讨论】:

to_be_bytes() 在小端系统上将交换字节 【参考方案1】:

Big endian 意味着首先存储(或传输)高字节,即在最低地址。 Intel 处理器是小端的,这意味着低字节存储在低地址中。

每个都有一些优点,但通常首选大端,这就是为什么网络协议和可移植数据格式通常是大端的原因。为了与旧版本兼容,英特尔仍然是小端。一些 CPU 具有可以在两者之间切换的模式,但英特尔从未这样做过。

【讨论】:

如果我的系统是小端(有英特尔 CPU),那么为什么我在内存中看到的一切都是大端?例如,内存中的 16 是发送给我的真实 16(以 BCD 格式)。此外,在我的示例中,如果我希望 first 在设备间始终保持为0x00,我是否必须使用 to_ne_bytes()? @Blue 您正在查看一大块原始字节。当然,字节的顺序与您收到它们的顺序相同。只有当您将这些字节解释大于字节时,字节序才会发挥作用。如果您只逐字节查看数据,那么它在每个架构上看起来都是一样的。 align_to 将以本机格式对 0x00 0x44 进行分组,对于 Intel 来说,低字节在前,高字节在后 = 0x4400to_be_bytes 将首先提取高(大端)字节(0x44),然后是低字节(0x00)。在转换为 u16 之前,您可能希望按照架构所需的方式获取字节顺序。【参考方案2】:

很难确切知道您的期望出了什么问题,但我会尝试解释这里发生了什么。

当您执行buf.align_to() 时,不会进行任何转换,字节会按原样重新解释。所以entry[0](假设它对齐的)将作为00 44存储在内存中。你的系统很可能是一个小端架构,所以entry[0]17408

fn main() 
    let buf = [0x00, 0x44];
    let result = u16::from_ne_bytes(buf); // also doesn't try to reinterpret bytes
    assert_eq!(result, 17408);

所以现在,entry[0] 是一个代表值 17408 的小端系统上的 u16。要使用大端表示获得相同的值,就像 to_be_bytes() 所做的那样,它将交换字节。


鉴于您的网络通信用例通常以大端顺序编码值,您可能希望使用entry[0].from_be() 来获得68 的正确值。

【讨论】:

我没有使用 from 函数。我正在使用 to 函数。 我会以不同的方式回答...如果您希望[first, second] 始终匹配与缓冲区中的字节顺序匹配的entry[0] 的字节顺序,请使用to_ne_bytes()。跨度>

以上是关于为啥 to_be_bytes() 和 to_le_bytes() 与我在这里期望的相反?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 __new__ 和 __init__ 在指向超类时表现不同?

为啥当我使用 [:] 时我的子类的 __getitem__ 和 __setitem__ 没有被调用?

为啥我的画布和/或我的照片图像不显示?

为啥不导入 Python [重复]

python multiprocessing问题,为啥输出结果和预期不一样?

为啥 def main(argv=[__name__]) 和 if __name__ == "__main__": sys.exit(main(sys.argv))?