19

バイト配列をshort/int / longに変換するときに、システムのエンディアンが重要かどうか疑問に思いました。コードがビッグエンディアンとリトルエンディアンの両方のマシンで実行されている場合、これは正しくありませんか?

short s = (b[0] << 8) | (b[1]);
int i = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3])
4

5 に答える 5

24

はい、エンディアンは重要です。リトルエンディアンでは、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_sntoh_l、エンディアンに関する決定が、socketそのようなことを認識しているOS実装にオフロードされます。デフォルトのネットワーク順序はビッグエンディアン(nin ntoh_x)であるため、バイト配列データをビッグエンディアンにするのが最も簡単な方法であることに注意してください。

OP(@Mike)で指摘されているように、boostエンディアン変換関数も提供します。

于 2012-12-03T06:28:29.093 に答える
4
// 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)
于 2016-03-14T14:14:39.520 に答える
1

これにはユニオンを使用できます。エンディアンは重要です。エンディアンを変更するには、ほとんどの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;
}
于 2016-09-03T11:25:23.643 に答える
0

intいいえ、エンディアンに関しては問題ありませんが、 16ビット幅しかない場合は問題が発生する可能性があります。

于 2012-12-03T06:25:22.637 に答える
0

指定した問題は、既存のバイト配列を使用している場合、すべてのマシンで正常に機能します。あなたは同じ答えになってしまうでしょう。

ただし、そのストリームを作成する方法によっては、エンディアンの影響を受け、思いどおりの数にならない場合があります。

于 2012-12-03T06:59:44.593 に答える