2016-12-03 10 views
1

私はバイナリファイルに小さな(16ビットまで)符号付き整数をシリアル化する必要があるプログラムを書いています。その一環として、整数を2バイトに分割する関数と、このバイトのペアを元の整数に戻す関数を記述する必要があります。Luaを使用してバイトのペアを符号付き16ビット整数に変換するにはどうすればよいですか?

私の心に来た最初のアイデアは、私はCにそれを解決する方法と同様に、この問題を解決することでした:Luaの整数は実際に64ビットとIを持っているので

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 

しかし、これらの関数は負の数値でブレークそれが負の数のために正しく動作するように、私のread_i16機能を変更するためのクリーンな方法は何でしょう

-- 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 

:下位16ビットのみを保持するのですか?

可能であれば、Cコードを書くことなく、純粋なLua 5.3を使用してこれを行うことをお勧めします。

+0

あなたのdump_i16は符号なしの値[0,256]を生成していますので、常にアサーションを失敗します。 – Moop

+0

あなたは 'read_i16(dump_i16(-20)== 65516'と' 65516 == 2^16 -20'なぜあなたは結果から '2^16'を引いてみませんか? – siffiejoe

+0

@Moop:そうです。真夜中にそれらを編集する前にテストしたはずです... – hugomg

答えて

2

ルア5.3には特別な変換機能があります。ビッグエンディアン順に整数-32768..32767長さ2の文字列にを変換する

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

(変換されている「a_string」の最初の2バイト)、それをバック変換するには:

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

ありがとう!私はこの答えを受け入れますが、それは実際には私の非常に特殊な問題を解決するものではありませんが、それは将来の読者に役立つ可能性が最も高いからです。 string.packのソースコードにも私が探していたトリックがありました:) – hugomg

1

署名を処理するには、論理右シフトが必要です。 Difference between >>> and >>を参照してください。ルアはそれを持っていないので、あなたは自分自身を持っています。 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 
+0

'dump_i16'の代わりに' read_i16'を修正する方法はありますか?私はb1とb2の両方が1バイトに収まるようにする必要があります。 – hugomg

0

read_i16を解決する1つの方法はstring.packによって内部的に使用される符号拡張アルゴリズムを使用することです:

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