Archive for 6月, 2010

6月 30th, 2010

バイトオーダー? 朏 64bit移? メボ

Posted in Linux by admin

圏 考: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