私は char a[4] を持っています:
a[0] = 0x76
a[1] = 0x58
a[2] = 0x02
a[3] = 0x00
そして、それを として印刷したいint
のですが、その方法を教えてもらえますか?
5 に答える
これは機能しますが、int、エンディアンなどのサイズに応じて異なる結果が得られます..
#include <stdio.h>
int main(int argc, char *argv[])
{
char a[4];
a[0] = 0x76;
a[1] = 0x58;
a[2] = 0x02;
a[3] = 0x00;
printf("%d\n", *((int*)a));
return 0;
}
これはきれいですが、エンディアン/サイズの問題がまだあります。
#include <stdio.h>
typedef union {
char c[4];
int i;
} raw_int;
int main(int argc, char *argv[])
{
raw_int i;
i.c[0] = 0x76;
i.c[1] = 0x58;
i.c[2] = 0x02;
i.c[3] = 0x00;
printf("%d\n", i.i);
return 0;
}
特定のエンディアンを強制するには、int
手動でビルドします。
int i = (0x00 << 24) | (0x02 <<< 16) | (0x58 << 8) | (0x76);
printf("%d\n", i);
組合はこれを行うための適切な方法だと思います。
#include <stdio.h>
#include <stdint.h>
union char_int {
char chars[4];
int32_t num;
};
int main() {
union char_int tmp;
tmp.chars[0] = 0x76;
tmp.chars[1] = 0x58;
tmp.chars[2] = 0x02;
tmp.chars[3] = 0x00;
printf("%d\n", tmp.num);
}
他のオプションは、次のようにビットごとの演算子|
と<<
左シフトを使用できます (読み取りコメントを理解するため):
int main(int argc, char *argv[])
{
char a[4];
int32_t i = 0; // 32 bits = 4 bytes
a[0] = 0x76;
a[1] = 0x58;
a[2] = 0x02;
a[3] = 0x00;
i = 0; // initial value must be `0`
i = i | a[0] << ( 3 * 8); // 0x76 => 0x76 00 00 00, gives i = 0x76 00 00 00
i = i | a[1] << ( 2 * 8); // 0x58 => 0x00 58 00 00, gives i = 0x76 58 00 00
i = i | a[2] << ( 1 * 8); // 0x02 => 0x00 00 02 00, gives i = 0x76 58 02 00
i = i | a[3] << ( 0 * 8); // 0x02 => 0x02
// => 0x00 00 00 02, gives i = 0x76 58 02 00
printf("Hex: %x\nDec: %d \n", i, i);
return 0;
}
出力:
$ gcc -Wall -pedantic yy.c
$ ./a.out
Hex: 76580200 <- "hex decimal"
Dec: 1985479168 <- "decimal"
注意:コードを統一するために、私はそのi = i | a[3] << ( 0 * 8);
ようi = i | a[3];
に書きました。
編集:
ああ、あなたはそれを次のようにすることができます:
i = 0 |
a[0] << ( 3 * 8) |
a[1] << ( 2 * 8) |
a[2] << ( 1 * 8) |
a[3] << ( 0 * 8);
ここを見てください:作業コードのCodepade 。
配列に格納されている値は、ビッグ エンディアンまたはリトル エンディアンの順序ですか? それを行う移植可能な方法は、シフトとマスクに基づいています。一般的なケースでは、上位ビットの一部が設定され、プレーンなchar
型が符号付きまたは符号なしである可能性があることに注意してください。
リトルエンディアン
int i = (a[3] << 24) | ((a[2] & 0xFF) << 16) | ((a[1] & 0xFF) << 8) | (a[0] & 0xFF);
ビッグエンディアン
int i = (a[0] << 24) | ((a[1] & 0xFF) << 16) | ((a[2] & 0xFF) << 8) | (a[3] & 0xFF);
これらを変更して、各用語が一貫して の形式になるようにすることができます((a[n] & 0xFF) << m)
。プレーンchar
が署名されていないことがわかっている場合は、マスク操作を削除できます。キャスト: を使用して、代わりにunsigned char *u = (unsigned char *)a;
逆参照することもできます。u
a
ビッグエンディアンまたはリトルエンディアンの整数として読みたい場合は、ビットシフトを行うだけです。
char a[4] = {0x76, 0x58, 0x02, 0x00};
// Big-endian:
uint32_t x = ((uint8_t)a[0] << 24) | ((uint8_t)a[1] << 16) | ((uint8_t)a[2] << 8) | (uint8_t)a[3];
// Little-endian:
uint32_t y = (uint8_t)a[0] | ((uint8_t)a[1] << 8) | ((uint8_t)a[2] << 16) | ((uint8_t)a[3] << 24);
ネイティブ エンディアン整数として読み取りたい場合は、配列を整数へのポインターにキャストし、それを逆参照することができます。前者は配列に対してのみ許可されていることに注意してくださいchar
-他のタイプの場合、そうするとCの厳密なエイリアシングルールが破られるため、安全でも移植可能でもありません. 例えば:
char a[4] = {0x76, 0x58, 0x02, 0x00};
// Cast to pointer to integer and dereference. This is only allowed if `a' is an
// array of `char'.
uint32_t x = *(uint32_t *)a;
または、ユニオンを使用するかmemcpy()
、データのみを直接使用することもできます。a が 8 ビットである限り、これらは両方とも安全で移植可能ですchar
(ビット単位のサイズはマクロによって与えられますCHAR_BIT
)。
char a[4] = {0x76, 0x58, 0x02, 0x00};
uint32_t x;
// Copy the data directly into x
memcpy(&x, a, sizeof(x));
// Use a union to perform the cast
union
{
char a[4];
uint32_t x;
} u;
memcpy(u.a, a, sizeof(a));
// u.x now contains the integer value
すべてのシステムで が 4 バイトであるとは限らないuint32_t
ため、上記のすべての例でを使用したことに注意してください。int
型uint32_t
はヘッダー ファイル<stdint.h>
で定義され、コンパイラで定義されている場合は、32 ビット幅であることが保証されます。