バイト配列をshort/int / longに変換するときに、システムのエンディアンが重要かどうか疑問に思いました。コードがビッグエンディアンとリトルエンディアンの両方のマシンで実行されている場合、これは正しくありませんか?
short s = (b[0] << 8) | (b[1]);
int i = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3])
バイト配列をshort/int / longに変換するときに、システムのエンディアンが重要かどうか疑問に思いました。コードがビッグエンディアンとリトルエンディアンの両方のマシンで実行されている場合、これは正しくありませんか?
short s = (b[0] << 8) | (b[1]);
int i = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3])
はい、エンディアンは重要です。リトルエンディアンでは、shortまたはintの上部に最上位バイトがあります。つまり、shortの場合はビット8〜15、intの場合は24〜31です。ビッグエンディアンの場合、バイト順序を逆にする必要があります。
short s = ((b[1] << 8) | b[0]);
int i = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
これは、バイト配列がリトルエンディアン順であることを前提としていることに注意してください。バイト配列と整数型の間のエンディアンと変換は、CPUのエンディアンだけでなく、バイト配列データのエンディアンにも依存します。
これらの変換を、システムのエンディアンを(コンパイルフラグを介して、または実行時に)認識し、変換を正しく実行する関数でラップすることをお勧めします。
さらに、バイト配列データの標準(たとえば、常にビッグエンディアン)を作成し、を使用するsocket
ntoh_s
とntoh_l
、エンディアンに関する決定が、socket
そのようなことを認識しているOS実装にオフロードされます。デフォルトのネットワーク順序はビッグエンディアン(n
in ntoh_x
)であるため、バイト配列データをビッグエンディアンにするのが最も簡単な方法であることに注意してください。
OP(@Mike)で指摘されているように、boost
エンディアン変換関数も提供します。
// on little endian:
unsigned char c[] = { 1, 0 }; // "one" in little endian order { LSB, MSB }
int a = (c[1] << 8) | c[0]; // a = 1
// ------------------------------------------------ ----------------------------
// on big endian:
unsigned char c[] = { 0, 1 }; // "one" in big endian order { MSB, LSB }
int a = (c[0] << 8) | c[1]; // a = 1
// ------------------------------------------------ ----------------------------
// on little endian:
unsigned char c[] = { 0, 1 }; // "one" in big endian order { MSB, LSB }
int a = (c[0] << 8) | c[1]; // a = 1 (reverse byte order)
// ------------------------------------------------ ----------------------------
// on big endian:
unsigned char c[] = { 1, 0 }; // "one" in little endian order { LSB, MSB }
int a = (c[1] << 8) | c[0]; // a = 1 (reverse byte order)
これにはユニオンを使用できます。エンディアンは重要です。エンディアンを変更するには、ほとんどのcコンパイラによって組み込みとして提供されるx86 BSWAP命令(または別のプラットフォームの類似物)を使用できます。
#include <stdio.h>
typedef union{
unsigned char bytes[8];
unsigned short int words[4];
unsigned int dwords[2];
unsigned long long int qword;
} test;
int main(){
printf("%d %d %d %d %d\n", sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long));
test t;
t.qword=0x0001020304050607u;
printf("%02hhX|%02hhX|%02hhX|%02hhX|%02hhX|%02hhX|%02hhX|%02hhX\n",t.bytes[0],t.bytes[1] ,t.bytes[2],t.bytes[3],t.bytes[4],t.bytes[5],t.bytes[6],t.bytes[7]);
printf("%04hX|%04hX|%04hX|%04hX\n" ,t.words[0] ,t.words[1] ,t.words[2] ,t.words[3]);
printf("%08lX|%08lX\n" ,t.dwords[0] ,t.dwords[1]);
printf("%016qX\n" ,t.qword);
return 0;
}
int
いいえ、エンディアンに関しては問題ありませんが、 16ビット幅しかない場合は問題が発生する可能性があります。
指定した問題は、既存のバイト配列を使用している場合、すべてのマシンで正常に機能します。あなたは同じ答えになってしまうでしょう。
ただし、そのストリームを作成する方法によっては、エンディアンの影響を受け、思いどおりの数にならない場合があります。