【问题标题】:Should I worry about bit order?我应该担心位顺序吗?
【发布时间】:2020-06-09 22:29:00
【问题描述】:

我在图书馆的设计中达到了一个让我对字节序感到恐惧的地步。
我可以轻松处理字节顺序,但是位顺序在我的代码中引入了巨大的复杂性。

我正在做的是将uint 转换为字节,以网络字节顺序(大端)。
但是,我将最重要的碎屑(2 位,从第一个 [最重要] 字节开始)用于其他内容,存储另一个数字。

通常,我使用这些行来编写和读取面包屑:

bytes[0] |= 0xC0 // Writing 11 to the most significant crumb. It could be 10 or 01 too. Before the disjunction, I know those two bits are 0.  
(bytes[0] & 0xC0) >> 6 // Getting the most significant crumb and shifting it to the right, in the least significant place.

对我来说,所有这些似乎都假设最重要的位在前。
如果没有,我这对操作基本上会把 00000011 变成 00001100,这不是我需要的值。
这些数据存储在一个文件中,可以在其他地方访问。如果存储机和读取机使用不同的位顺序,读取器就会得到垃圾。

我也不记得曾经读过一段对位顺序做出反应的代码。

所以,我的问题是:我是偏执狂还是我的 C# 库可以在 LSB 优先的机器上使用? (在 .NET 或 Mono 下;Windows、Unix、Android、iOS 等)
如果是这样,我怎样才能有效地处理这些可能性并能够正确检索我的 2 位数字?

【问题讨论】:

  • Endian 不影响位序,只影响字节序。
  • en.wikipedia.org/wiki/Bit_numbering 好像每个人都认为最重要的位在前……
  • 认为所有 .NET 实现都应该以相同的方式对待字节序(我认为这是规范的一部分),但是,我可能错了。但是,我会考虑在图书馆中唯一考虑错误字节序的地方是图书馆的输入点,即。任何公开的方法并接受可能出错的东西。
  • 没有“第一”。最重要的位是.. 最重要的。这既不是第一个也不是最后一个。您无法在系统上进行任何可以显示差异的测量 - 整数运算符始终以完全相同的方式工作。
  • @harold 是的:您只需将原始字节读取为字节,例如使用unsafe 代码将int 变量视为byte*

标签: c# bit-manipulation


【解决方案1】:

由于您正在使用诸如移位操作之类的东西:您很好。 Endianness 不会影响这些:它们在任何 *-endian 架构上的行为都相同 - 简单地说:它的内部工作方式可能会在 CPU 之间发生变化,但您总是会得到相同的答案,就像从常规代码中看到的那样。

字节序实际上只影响直接值到字节的解释,例如使用unsafe 代码或BitConverter 获取(或设置)intdouble 后面的原始字节,显式布局“ union" 结构,重叠不同字段的字节。如果您不做那种类型的事情,那么您无需担心 CPU 字节序。

【讨论】:

  • 如果在计算机 A 上我写 11000000,这意味着它是 128 + 64 = 192,而计算机 B 使用相反的顺序,它将读取数字 3。我将如何解决这个问题?
  • @Vercas 实际上,在大多数字节序讨论中,存在超过 192 与 -1073741824 的冲突(假设是 int);但是您只会永远看到,如果您正在读取原始数据:例如,从文件或套接字读取 4 个字节并通过 unsafe 代码将它们直接强制到 int。在这种情况下,解决方法是:确保在从文件或套接字读取原始数据时考虑字节序。在常规 C# 中,包括算术和按位运算:它的行为总是像 192
  • @Vercas 强调:字节序几乎总是主要与字节顺序有关,而不是位顺序
  • System.IO.Stream 的每个实现是否都知道源是否以相反的顺序出现?我能想到的唯一方法是在我的数据 blob 的开头存储一个“魔术”字节,这将具有一个已知值。如果在读取时碰巧与预期不同,则必须在每个字节中翻转所有位。另外,我之所以说 3,是因为我专门讨论的是字节内的位。我已经在我的代码中考虑了字节顺序。
  • @Vercas 不,流根本没有的概念:它们只是一个字节序列。所以重要的问题是:字节的顺序是什么?位顺序不是通常意义上的字节序。您无需担心这种变化。
【解决方案2】:

您不必担心位顺序。但是位是在 CPU 中处理的,对应的位操作对外是一样的。

当您向右移动时,它总是向最低有效位移动。如果最低位在CPU内部实际上是向左移动,物理位向左移动,但是CPU外部的数字的表示仍然是最低位向右,运算符的含义是在任何 CPU 上都一样。

当您按位或使用0xC0 时,位在哪里并不重要,因为值中的最高有效位和0xC0 中的最高有效位在同一个位置。

【讨论】:

  • 好吧,但真正的问题是,当相同的数据从 LSB-0 传输到 MSB-0 机器时,位会被误解。
  • @Vercas:无论您如何传输数据,介质都有特定的位顺序,并且在每一步都会转换值。最后字节值还是一样的意思。
  • 你所说的“翻译”——我无法想象它会在哪里以及如何发生。
  • @Vercas:例如,如果您通过网络发送数据,那么这些位是串行发送的,因此没有左或右,只有第一个和最后一个。另一方面,它必须被转换回一个字节,所以它必须知道哪一位去哪里,即哪一位是最重要的。
  • @Vercas:标准中定义了您用于移动数据的任何介质。网络协议定义了最重要的位在哪里。
猜你喜欢
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 2013-03-20
  • 2019-07-13
相关资源
最近更新 更多