【问题标题】:How can I convert a pair of bytes into a signed 16-bit integer using Lua?如何使用 Lua 将一对字节转换为有符号的 16 位整数?
【发布时间】:2016-12-03 02:13:34
【问题描述】:

我正在编写一个程序,该程序需要将小(最多 16 位)有符号整数序列化为二进制文件。作为其中的一部分,我需要编写一个可以将整数拆分为两个字节的函数,以及另一个可以将这对字节转换回原始整数的函数。

我想到的第一个想法是解决这个问题,就像我如何解决它 C:

function dump_i16(n)
  assert (-0x8000 <= n and n < 0x8000) -- 16 bit
  local b1 = (n >> 8) & 0xff
  local b2 = (n >> 0) & 0xff
  return b1, b2
end

function read_i16(b1, b2)
  assert (0 <= b1 and b1 <= 0xff) -- 8 bit
  assert (0 <= b2 and b2 <= 0xff) -- 8 bit
  return (b1 << 8) | (b2 << 0)
end

但是,这些函数会在负数上中断,因为 Lua 整数实际上有 64 位,而我只保留低 16 位:

-- Positive numbers are OK
print( read_i16(dump_i16(17)) ) -- 17
print( read_i16(dump_i16(42)) ) -- 42

-- Negative numbers don't round trip.
print( read_i16(dump_i16(-1)) )  -- 65535 = 2^16 - 1
print( read_i16(dump_i16(-20)) ) -- 65516 = 2^16 - 20

修改我的 read_i16 函数使其对负数正常工作的最简洁方法是什么?

如果可能的话,我宁愿使用纯 Lua 5.3 来完成这项工作,而无需编写 C 代码。

【问题讨论】:

  • 您的 dump_i16 正在生成无符号值 [0,256),因此您的断言总是会失败
  • 你说过read_i16(dump_i16(-20) == 6551665516 == 2^16 -20。为什么不直接从结果中减去2^16...?
  • @Moop:你是对的。我应该在半夜编辑之前测试一下……

标签: lua bit-manipulation


【解决方案1】:

Lua 5.3 有特殊的转换功能。

将整数 -32768..32767 以大端顺序转换为长度为 2 的字符串:

local a_string = string.pack(">i2", your_integer)

将其转换回来(“a_string”的前两个字节正在被转换):

local an_integer = string.unpack(">i2", a_string)

【讨论】:

    【解决方案2】:

    你需要一个逻辑右移来处理这个标志。见Difference between >>> and >>。 Lua 没有,所以你自己做。由于 Lua 整数默认为 64,因此您将 64 减去您所做的移位数。

    function dump_i16(n)
       assert (-0x8000 <= n and n < 0x8000)
       local b1 = (n >> 8) & ~(-1<<(64-8))
       local b2 = (n >> 0) & 0xff
       return b1, b2
    end
    

    【讨论】:

    • 有没有办法修改read_i16而不是dump_i16?我需要 b1 和 b2 都适合单个字节。
    • Lua 5.2 不支持&lt;&lt;&gt;&gt; 风格的按位运算。能否为 Lua 5.2 添加解决方案?
    【解决方案3】:

    修复 read_i16 的一种方法是使用 string.pack 内部使用的符号扩展算法:

    function read_i16(b1, b2)
      assert (0 <= b1 and b1 <= 0xff)
      assert (0 <= b2 and b2 <= 0xff)
      local mask = (1 << 15)
      local res  = (b1 << 8) | (b2 << 0)
      return (res ~ mask) - mask
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-30
      相关资源
      最近更新 更多