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, 11
或 11, 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]
这不是我们想要的。
我开始使用 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, 11
或 11, 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]
这不是我们想要的。