0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rubyでビッグエンディアン64bit整数をunpackする

Last updated at Posted at 2016-05-15

背景

Rubyでバイナリ列をパースするにはString#unpackメソッドを使う。
この際には、変数の型(32bit符号付き整数、倍精度浮動小数点数など)と、エンディアンを指定する。

例えば、ファイルからビッグエンディアンの倍精度浮動小数点数を読み込みたい場合、以下のようにする。

read_double.rb
io = File.open(ARGV[0], 'rb')
b = io.read(8)    # 8 byte読む
p b.unpack("G")   # バイト列を 64bit double big-endian として解釈する

上の例の "G" というのがpackテンプレート文字列と呼ばれるもので、エンディアンと型を指定するもの。
パックテンプレート文字列の一覧

上記のページを見てもらうとわかるように、ビッグエンディアンの64bit符号付き整数については方法が提供されていない。(16,32bitについては方法が提供されている。)
そのため、64bit整数については自前で実装する必要がある。

(2022/8/12 追記)コメントで方法を教えていただきました。(@Nabetaniさんありがとうございます)
以下のようにすることでビッグエンディアンを指定できます。

b.unpack("q>")

公式のドキュメントにも
「強制的にエンディアンを指定したいときは、 リトルエンディアンなら< ビッグエンディアンなら> を後ろにつけます」と書いてありました。
以下の自前で実装する方法は不要になりました。
(追記おわり)

64bit signed integerに対して自前で実装する方法

以下のようなメソッドを用意する。

read_signed64int.rb
def read_signed64int(b)
  big_endian = [1].pack("s") == [1].pack("n")
  # s: system-dependent int16_t, n: big-endian 16bit integer
  big_endian ? b.unpack("q") : b.reverse.unpack("q")
  # q: long long (符号付き整数, エンディアンと long long のサイズに依存)
end

[1].pack("s") == [1].pack("n") で実行しているシステムのエンディアンを確認。
システムがリトルエンディアンの場合は、バイト列をreverseでリトルエンディアンに変更してから unpack("q") でlong longとして解釈する。

参考

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?