24 位无符号整数

24 Bit Unsigned Integer

我开始使用 HART(高速可寻址远程传感器)协议,我发现了一些不同的东西,我试图理解它,更准确地说是 uint24。我知道这个结构在内部使用 UInt32 来存储和大多数其他常见的预期整数功能,因此使用 24 位整数不会节省内存。但我的问题是如何将 UInt32 转换为这种特定类型,我在 Javascript 中找到了这些代码行,但我不知道那些左移的目的是什么。

var getUint24 = function(bytes)
{
    return (DataView(bytes.buffer).getUint16(0) << 8) + DataView(bytes.buffer).getUint8(0 + 2);
}

此外,我发现了这个将数字转换为 4 个字节的函数。我也不知道这些转移的目的是什么,但也许如果我理解这些我可以创建我自己的函数版本,将一个简单的数字 ex: 4 转换成他的 uint24 版本。

/**
 *
 * @function ToBytesInt32 "Convert number to 4 bytes (eg: ToBytesInt32(2) returns 00 00 00 02"
 * @param {number} num The input value
 * @return {byte array}
 */
function ToBytesInt32BigEndian(num) {
    if (isNaN(num)) {
        throw "ToBytesInt32 received Nan! Called from: " +
        testUtils.StrReplace.caller.toString().split('\n')[0];
    }
    arr = [
        (num & 0xff000000) >> 24,
        (num & 0x00ff0000) >> 16,
        (num & 0x0000ff00) >> 8,
        (num & 0x000000ff)
    ];
    return arr;
}

如果有人能帮助我理解那些转变的目的,我会很感激,也非常欢迎 C/C++ 版本。

简答

  • 向左 << 移位是用零填充有效位,以便将来连接成单个值;
  • >> 移位是将值的段提取为较小数据类型的一部分(在应用掩码之后进行);

摘要

当 reading/writing 帧小于值的长度时,

Shift & sum 是获取 pack/unpack 值的方法。假设我们有 4 位值:1011。我们只能通过 2 位帧读取它:[10], [11].

假设我们从左到右读取流。

# offset 0 bits
a = stream(0)      # a = 10
a << 2             # a = 1000

b = stream (2)     # b = 11

return a + b       # 1000 + 11 = 1011

你还应该注意BE/LE (Big/Little Endian)。在不同的字节序中,值 1011 可能在流中显示为 10, 1111, 10.

getUint24 示例

getUint24 示例中,我们将 24 位值打包为序列,如 [16 bit, 8 bit]。让我们把它画成 [XY, Z] 其中单个字母是 1 个字节。

# offset 0 bytes
a = DataView(bytes.buffer).getUint16(0)      # a = XY
a << 8                                       # a = XY0

# offset 2 bytes
b = DataView(bytes.buffer).getUint8(2)       # b = Z

return a + b                                 # XY0 + Z = XYZ

而且 bytes.buffer 可能会将值保持为 [XY, Z][Z, XY]getUintX(offset) 向我们隐藏了这些细节。但是如果你想编写自己的转换器,你需要调查你的情况是什么格式。

ToBytesInt32BigEndian 示例

这里我们看到另一个关于打包值的问题——应用掩码。

假设我们有 32 位值 AB CD EF 12。我们可以应用掩码来提取所需的值段。

例如,如果我们有 3 位值 011 并且想要获取第二位的值,我们需要应用 &-mask,其中根据 1 评估的主题位保持原始值,而其余位评估针对 0 将任何值转换为 0.

masked    = 011 & 010    # 010
bit_value = masked >> 1  # 001

和我们的一样ABCDEF12

x = 0xABCDEF12 & 0xFF000000   # x = 0xAB000000
x >> 24                       # x = 0x000000AB
...

这样我们将得到数组[0xAB, 0xCD, 0xEF, 0x12]。没有移动我们得到数组 [0xAB000000, 0x00CD0000, 0x0000EF00, 0x00000012] 这不是我们想要的。