バイト順(byte order)


コンセプト
バイト順とは、ハードウェアにおけるマルチバイトの値の格納順である.一般に大端(big-endian)と小端(little-endian)に分けられる.
マクロ:高バイト(Most significant bit)を先に記憶する、あるいは、高バイトは低アドレス、低バイトは高アドレスに記憶する.
小端:まず低バイト(Least significant bit)を記憶する、あるいは低バイトは低アドレス、高バイトは高アドレスに記憶する.
4バイトの数字0 x 0100200304を例にとると、開始アドレスはnであり、次の表を参照してください.
大端
アドレス

n
0x01
n+1
0x02
n+2
0x03
n+3
0x04
小端
アドレス

n
0x04
n+1
0x03
n+2
0x02
n+3
0x01
大端または小端はCPUによって決定されます.次の表を参照してください.
大端
小端
そのうちの1つ
AVR32 FR-V H8300 PA-RISC S390 Motorola 680x0 SPARC
Alpha CRIS Blackfin Intel 64 IA-32 (x86) MN10300
ARM SuperH (sh) M32R MIPS Xtensa PowerPC
PowerPCについては、大端と小端のどちらを使用するように構成することができ、Linuxは大端を選択する.
大端または小端の記憶方式は、アプリケーションを書くプログラマーにとって透明であり、関心を持つ必要はない.一方、2台の記憶方式が異なる機器間でマルチバイトの値を伝送する場合は、同一の記憶方式を用いる.TCP/IPプロトコルについては、マクロ方式を用いる.(すべての通信プロトコルではなく、例えば?fix me!)
ビット操作はバイト順に関係しますか?
ビット操作は加減乗除のようにデータの格納方式には関係ない.以下のテストコードと出力を参照してください.
#include 

union u {
    int i; 
    char c[sizeof(int)];
}; 

void printU(union u* pu);

int main() {
    union u foo;
    foo.i = 1;
    if (foo.c[0] == 1)
        printf("Little endian
"); else printf("Big endian
"); foo.i = 270; printU(&foo); printf("%d
", foo.i / 256); printf("%d
", foo.i >> 8); printf("%d
", foo.i % 256); printf("%d
", foo.i & 0xff); return 0; } void printU(union u* pu) { int j; for (j = 0; j < sizeof(int); ++j) printf("%.2x", pu->c[j]); printf("
"); }

プログラム出力:
aix>xlc t.c
aix>./a.out
Big endian
0000010e
1
1
14
14

テスト
コードテスト
次のコードを使用して、コンピュータが大端なのか小端なのかを検出できます.
#include 

int main() {
    union {
        int i;
        char c[sizeof(int)];
    } foo;

    foo.i = 1;
    if (foo.c[0] == 1)
        printf("Little endian
"); else printf("Big endian
"); int j; for (j = 0; j < sizeof(int); ++j) printf("%.2x", foo.c[j]); printf("
"); return 0; }

もしfoo.c[0]が1であることは、整数iの低バイトが低アドレスに格納されているため、小端であることを示す.(配列中、アドレス&foo.[1]は必ず&foo.[0]より大きいですか?fix me!)
私の机械の使うCPUはintelで、それぞれwin 7とubuntuの上でテストして、出力はすべて:
Little endian
01000000

低バイトの1は低アドレス&fooに格納.c[0].
もう一つの大きな端の機械を見つけて、出力は:
Big endian
00000001

低バイトの1は高アドレス&fooに格納.c[3]
デバッグでのメモリの表示
まず簡単なテストコードを書きます.
int main() {
    int i = 0x01020304;
    return 0;
}

Intelカーネルの小端でgdbを使用してデバッグします.
mjn@mjn-desktop:~/codes/c/test$ gcc -g byteorder2.c
mjn@mjn-desktop:~/codes/c/test$ gdb ./a.out
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
...
Reading symbols from /home/mjn/codes/c/test/a.out...done.
(gdb) start
Temporary breakpoint 1 at 0x80483ba: file byteorder2.c, line 2.
Starting program: /home/mjn/codes/c/test/a.out 

Temporary breakpoint 1, main () at byteorder2.c:2
2	    int i = 0x01020304;
(gdb) n
3	    return 0;
(gdb) x/4xb &i
0xbffff404:	0x04	0x03	0x02	0x01

gdbにおける「x/4 xbアドレス」は、「アドレス」から4バイトを16進数で表示する内容を表す.低バイトの0 x 04は低アドレスなので、小端である.
大規模な環境では、dbxを使用してデバッグします.
AIX5.3-mjn > xlc -g byteorder2.c
AIX5.3-mjn > dbx ./a.out
Type 'help' for help.
reading symbolic information ...
(dbx) stop in main
[1] stop in main
(dbx) run
[1] stopped in main at line 2
    2       int i = 0x01020304;
(dbx) n
stopped in main at line 3
    3       return 0;
(dbx) &i /4c
0x2ff22850:  '^A' '^B' '^C' '^D'
(dbx) &i /2x
0x2ff22850:  0102 0304
(dbx) &i /1X
0x2ff22850:  01020304

'&i/4 c'は、アドレス&iの後4バイトを文字で表示する内容を表す.ここで、′^A′の値は1である、′^D′の値は4であり、低バイト0 x 04は高アドレスに記憶するので、大端である.
References:
Bruce Blinn: Byte Order
ウィキペディア:Endianness