6月 30th, 2010
バイトオーダー? 朏 64bit移? メボ
圏 考:Linuxアプリケーションぜ 64ビット・システムへの移植
http://www.ibm.com/developerworks/jp/linux/library/l-port64/
上記URLにも掲載されていますが、アプリケーションを64bit移? する際の注? 点がいぜ つかあります。このうち、ネットワークプログラミングに頻出するバイトオーダーの? 朏 に関してメモを残します。簡単に? うと、ビッグエンディアン方? のネットワークバイトオーダーをLinuxのリトルエンディアン方? のバイトオーダーに? 朏 する際に使用する関? “ntohl”, “htonl”は、64bit Linux環? では正しく変朏 されないという事象の? 書です。以? 、サンプルプログラムと? 行結果を残します。
§ x86 64bit
# uname -m x86_64
# cat test.c #include <stdio .h> #include <byteswap .h> int main(){ printf("int: %d\n", sizeof(int)); printf("long: %d\n", sizeof(long)); printf("int*: %d\n\n", sizeof(int*)); int i = 0x12345678; long l = 0x0123456789abcdef; long m = 0x0123456789abcdef; char* c = (char *)&i; char* d = (char *)&l; char* e = (char *)&m; if (*(char *)&i == 0x12){ printf ("Big endian\n\n"); } else if(*(char *)&i == 0x78){ printf ("Little endian\n\n"); } printf("[1]int org:\t%X : %X : %X : %X\n" , c[0] , c[1] , c[2] , c[3]); i = htonl( i ); printf("[2]int htonl:\t%X : %X : %X : %X\n\n" , c[0] , c[1] , c[2] , c[3]); printf("[3]long org:\t%X : %X : %X : %X : %X : %X : %X : %X\n" , \ d[0] , d[1] , d[2] , d[3], d[4], d[5], d[6], d[7]); l = bswap_64( l ); printf("[4]long bswap_64:\t%X : %X : %X : %X : %X : %X : %X : %X\n\n" , \ d[0] , d[1] , d[2] , d[3], d[4], d[5], d[6], d[7]); printf("[5]long org:\t%X : %X : %X : %X : %X : %X : %X : %X\n" , \ e[0] , e[1] , e[2] , e[3], e[4], e[5], e[6], e[7]); m = htonl( m ); printf("[6]long htonl:\t%X : %X : %X : %X : %X : %X : %X : %lX\n" , \ e[0] , e[1] , e[2] , e[3], e[4], e[5], e[6], e[7]); return 0; }
# gcc test.c && ./a.out int: 4 long: 8 int*: 8 Little endian [1]int org: 78 : 56 : 34 : 12 [2]int htonl: 12 : 34 : 56 : 78 [3]long org: FFFFFFEF : FFFFFFCD : FFFFFFAB : FFFFFF89 : 67 : 45 : 23 : 1 [4]long bswap_64: 1 : 23 : 45 : 67 : FFFFFF89 : FFFFFFAB : FFFFFFCD : FFFFFFEF [5]long org: FFFFFFEF : FFFFFFCD : FFFFFFAB : FFFFFF89 : 67 : 45 : 23 : 1 [6]long htonl: FFFFFF89 : FFFFFFAB : FFFFFFCD : FFFFFFEF : FFFFFFFF : FFFFFFFF : FFFFFFFF : FFFFFFFF
[5][6]で示した結果のように、64bit環? においぜ “htonl”関数では正しぜ バイトオーダーの? 朏 がされていないのが゜ かります。”htonl”、”ntohl”は、4バイト整数の? 朏 に使用され、同様に、”htons”、”ntohs”は、2バイト整数に使用されますが、64bit環? ぜ 8バイトデータサイズとなるlong型やポインターには使用出来ないからです。[3][4]のように正しく変朏 する為には、Linux上でぜ “bswap_64″マクボ (/usr/include/bits/byteswap.h)を使用します。以? のように、データサイズが4バイトを超えない32bit環? では問題なぜ 動作します。
§ i686 32bit
# uname -m i686
# cat test.c #include <stdio .h> #include <byteswap .h> int main(){ printf("int: %d\n", sizeof(int)); printf("long: %d\n", sizeof(long)); printf("int*: %d\n\n", sizeof(int*)); int i = 0x12345678; long l = 0x12345678; long m = 0x12345678; char* c = (char *)&i; char* d = (char *)&l; char* e = (char *)&m; if (*(char *)&i == 0x12){ printf ("Big endian\n\n"); } else if(*(char *)&i == 0x78){ printf ("Little endian\n\n"); } printf("[1]int org:\t%X : %X : %X : %X\n" , c[0] , c[1] , c[2] , c[3]); i = htonl( i ); printf("[2]int htonl:\t%X : %X : %X : %X\n\n" , c[0] , c[1] , c[2] , c[3]); printf("[3]long org:\t%X : %X : %X : %X\n" , d[0] , d[1] , d[2] , d[3]); l = bswap_32( l ); printf("[4]long bswap_32:\t%X : %X : %X : %X\n\n" , d[0] , d[1] , d[2] , d[3]); printf("[5]long org:\t%X : %X : %X : %X\n" , e[0] , e[1] , e[2] , e[3]); m = htonl( m ); printf("[6]long htonl:\t%X : %X : %X : %X\n" , e[0] , e[1] , e[2] , e[3]); return 0; }
# gcc test.c && ./a.out int: 4 long: 4 int*: 4 Little endian [1]int org: 78 : 56 : 34 : 12 [2]int htonl: 12 : 34 : 56 : 78 [3]long org: 78 : 56 : 34 : 12 [4]long bswap_32: 12 : 34 : 56 : 78 [5]long org: 78 : 56 : 34 : 12 [6]long htonl: 12 : 34 : 56 : 78