12
14

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 5 years have passed since last update.

[バイトオーダー]ビックエンディアン/リトルエンディアン

Last updated at Posted at 2018-12-01

280px-Big-Endian-ja.svg.png

概要

エンディアンについて調べたことのアウトプット

データをバイト単位で配置する際のやり方の一つで二つの違いの結論だけ述べると、

ビッグエンディアン:「最初のバイトからデータを並べる」やり方
リトルエンディアン:「最後のバイトからデータを並べる」やり方

といった特性を持つ並べ方である。
詳しくは下記に記載していきます。

エンディアンとは

プログラムを動かすときに、データは1バイト単位(=8ビット)で 記憶されていきます。
2バイト以上のデータを保存する時に、どのような順序で記憶していくか、という方法を示すのがエンディアンになります 。
エンディアンはCPUによって決まっています。

ビックエンディアン、ミドルエンディアン、リトルエンディアンといった種類がある。

ビックエンディアンとリトルエンディアンを例に挙げて説明。
long型の変数として2882400001 = 0xABCDEF01という数があるとする。
この場合それぞれの並び順序は

ビックエンディアン: AB CD EF 01
リトルエンディアン: 01 EF CD AB

ビッグエンディアンの方はデータの上の方から準に詰めていくのに対し、
リトルエンディアンは下の方から順に詰めていきます。

エンディアンについて調べてみた

以下はC言語でエンディアンを特定するためのソース。
lscpuコマンドを使用すればわかるが今回はエンディアン変換まで行いたいので割愛。
共用体を用いてバイトオーダーを確認(参考:wiki)

endian.c
#include <stdint.h>
#include <stdio.h>

int main (int argc, char **argv) {
    union {
        uint32_t b4;
        uint16_t b2[2]
        uint8_t  b1[4]
    } bytes ;

    bytes.b4 = 0x12345678 ;
    printf ("bytes.b4: %08X\n", bytes.b4) ;
    printf ("bytes.b2: %04X, %04X\n", bytes.b2[0], bytes.b2[1]) ;
    printf ("bytes.b1: %02X, %02X, %02X, %02X\n", bytes.b1[0], bytes.b1[1], bytes.b1[2], bytes.b1[3]) ;
    return 0 ;
}

上記をコンパイルして実行する。
すると並び順が入れ替わっているのでリトルエンディアンであることが分かる。

$ gcc endian.c
$ ./a.out
bytes.b4: 12345678
bytes.b2: 5678, 1234
bytes.b1: 78, 56, 34, 12

ちなみに検証機はwindows10のインテル系CPUなので当然である。
残念ながら自宅にはビックエンディアンでの検証ができないのでいったん締め
次はByte swappingについて調べる。

Byte swappingとは

エンディアンを相互に変換すること、つまり、
ビッグエンディアン⇒リトルエンディアン
または
リトルエンディアン⇒ビッグエンディアン
のことをByte swappingという

エンディアン変換は以下のようなツールもあるが今回は自前で作成してみる。
http://web.save-editor.com/tool/wse_hex.html

byte_swap.c
#include <stdio.h>
#include <stdint.h>

#define BASENUM 0xABCD0123

void check_endian() {
        int x = 1;
        if( *(char *)&x ){
                fprintf(stdout, "little endian\n");
        }else{
                fprintf(stdout, "big endian\n");
        }
}

uint32_t byte_swap(uint32_t value) {
        uint32_t ret;
        ret  = value              << 24;
        ret |= (value&0x0000FF00) <<  8;
        ret |= (value&0x00FF0000) >>  8;
        ret |= value              >> 24;
        return ret;
}

int main(int argc, char* argv[]) {
        unsigned int value = BASENUM;

        check_endian();

        fprintf(stdout, "base : %08x\n", value);
        fprintf(stdout, "swap ; %08x\n", byte_swap(value));

        return 0;
}

上記の実行結果は下記のようになります。
エンディアンの特定とbyte swappingを実装してみました。

$ ./a.out
little endian
base : abcd0123
swap : 2301cdab

エンディアン特定については全く思いつかずで下記を参考にしています。
大変わかりやすい記事ですので是非ご参照ください。
http://torasukenote.blog120.fc2.com/blog-entry-105.html

プロセッサ以外のバイトオーダ

プロセッサ界隈以外でもバイトオーダーという言葉は使われることがあります。
それは「ネットワークバイトオーダ」です。
TCP/IPなどの通信プロトコルはバイト配列を扱いますが、MACやIPアドレスといったデータは多バイトデータですので、
通信路に出力する順番を決める必要があります。
ちなみにTCP/IPのネットワークバイトオーダはビッグエンディアン。

hton(3)やhtols(3)が変換にあたります。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/byteorder.3.html

関数 説明
uint32_t htonl(uint32_t hostlong) 32bitのホストバイトオーダーをネットワークバイトオーダーに変換
uint16_t htons(uint16_t hostshort) 16bitのホストバイトオーダーをネットワークバイトオーダーに変換
uint32_t ntohl(uint32_t netlong) 32bitのネットワークバイトオーダーをホストバイトオーダーに変換
uint16_t ntohs(uint16_t netshort) 16bitのネットワークバイトオーダーをホストバイトオーダーに変換

ビックエンディアンはどこで

ビックエンディアンは自宅で用意できないと思ったが調べてみるとJavaの仮想マシンはビックエンディアンらしい。
他にもIBM社のメインフレームもビックエンディアンとのこと。
(参考:http://e-words.jp/w/%E3%83%93%E3%83%83%E3%82%B0%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3.html)

  • JVM
  • IBMメインフレームワーク
  • TCP/IPのネットワークオーダー

上記3点は少なくともビックエンディアン。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?