int i=512;
char *c = (char *)&i;
c[0] =1;
printf("%d",i);
これは「513」と表示され、i に 1 が加算されます。
int i=512;
char *c = (char *)&i;
c[1] =1;
printf("%d",i);
これは 256 を表示します。これを 2 で割ります。誰か理由を説明してもらえますか? どうもありがとう
int i=512;
char *c = (char *)&i;
c[0] =1;
printf("%d",i);
これは「513」と表示され、i に 1 が加算されます。
int i=512;
char *c = (char *)&i;
c[1] =1;
printf("%d",i);
これは 256 を表示します。これを 2 で割ります。誰か理由を説明してもらえますか? どうもありがとう
バイナリで表現された 32 ビット数 512 は、次のとおりです。
00000000000000000000001000000000
2 の 9 乗は 512 であるためです。通常、ビットは右から左に読み取られます。
2進数の他の10進数は次のとおりです。
0001 = 1
0010 = 2
0011 = 3
0100 = 4
これを行う場合:
int i = 512;
char *c = (char *)&i;
おそらくご存知のように、4 バイト整数を文字の配列 (8 ビット バイト) として解釈しています。そうでない場合は、次のようになります。
&i
変数のアドレスを取得しますi
。
(char *)&i
char 型へのポインターに再解釈 (またはキャスト) します。これは、配列のように使用できるようになったことを意味します。int
はマシン上で少なくとも 32 ビットであることがわかっているため、 を使用してそのバイトにアクセスできますc[0], c[1], c[2], c[3]
。
システムのエンディアンに応じて、数値のバイトが配置される場合があります。最上位バイトが最初 (ビッグ エンディアン) または最下位バイトが最初 (リトル エンディアン) です。x86プロセッサはリトル エンディアンです。これは基本的に、数字 512 が上記の例のように配置されていることを意味します。
00000000 00000000 00000010 00000000
c[3] c[2] c[1] c[0]
ビットを、メモリ内でのレイアウト方法に対応する個別の 8 ビット チャンク (バイト) にグループ化しました。ここでも右から左に読むことに注意してください。これにより、2 進数システムの規則を守ることができます。
現在、設定c[0] = 1
には次の効果があります。
00000000 00000000 00000010 00000001
c[3] c[2] c[1] c[0]
これは2^9 + 2^0 == 513
10進数です。
設定c[1] = 1
には次の効果があります。
00000000 00000000 00000001 00000000
c[3] c[2] c[1] c[0]
2 番目のバイト 00000010 を 00000001 で上書きしたため、これは2^8 == 256
10 進数です。
ビッグ エンディアンシステムでは、バイトはリトルエンディアンシステムとは逆の順序で格納されることに注意してください。これは、これらのマシンで実行した場合とはまったく異なる結果が得られることを意味します。
char は 8 ビットであり、512 はビット表現であることに注意してください。
512 = 10 0000 0000
あなたchar *c = (char *)&i;
が作るとき:
c[1] = 10
c[0] = 0000 0000
c[0] = 1 を実行すると10 0000 0001
、513 になります。
c[1] = 1 とすると、01 0000 0000
256 になります。
表示されているものが「奇妙」である理由を考える前に、コードを実行しているプラットフォームとそのエンディアンを考慮してください。
次に、次のことを検討してください
int main(int argc, char *argv[])
{
int i=512;
printf("%d : ", i);
unsigned char *p = (unsigned char*)&i;
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
char *c = (char *)&i;
c[0] =1;
printf("%d : ", i);
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
i = 512;
c[1] =1;
printf("%d : ", i);
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
return 0;
}
私のプラットフォーム (Macbook Air、OS X 10.8、Intel x64 Arch)
512 : 00020000
513 : 01020000
256 : 00010000
上記の内容とエンディアンについて読んだ内容を組み合わせると、私のプラットフォームがリトル エンディアンであることがはっきりとわかります。それで、あなたのものは何ですか?
ポインタint
を介してan をエイリアシングしており、aは 8 ビット幅 (1 バイト) であるため、割り当ては次のようになります。char
char
c[1] = 1;
の 2 番目のバイトを に設定i
し000000001
ます。バイト 1、3、および 4 ( の場合sizeof(int) == 4
) は変更されません。以前は、その 2 番目のバイトは000000010
(リトルエンディアン アーキテクチャである x86 ベースのコンピューターを使用していると想定しているため) だったので、基本的には、設定された唯一のビットを 1 つ右にシフトしました。2で割ったものです。
リトル エンディアンのマシンと 32 ビットのコンパイラではint
、最初に次の 4 バイトが にありましたi
。
c[0] c[1] c[2] c[3]
00000000 00000010 00000000 00000000
割り当て後、次のi
ように設定されました。
c[0] c[1] c[2] c[3]
00000000 00000001 00000000 00000000
したがって、512 から 256 になりました。
これで、513 という結果になる理由が理解できるはずですc[0] = 1
:-) どのバイトが 1 に設定され、割り当てによって他のバイトがまったく変更されないかを考えてみてください。
これは、マシンがリトルエンディアンであるためです。つまり、最下位バイトが最初にメモリに格納されます。
あなたは言っint i=512;
た。512
は0x00000200
16 進数です (簡単にするために 32 ビット OS を想定しています)。i
16 進数のバイトとしてメモリに格納される方法を見てみましょう。
00 02 00 00 // 4 bytes, least-significant byte first
次に、同じメモリ位置を文字配列として解釈しますchar *c = (char *)&i;
-同じメモリ、異なる解釈:
00 02 00 00
c[0][1][2][3]
で変更c[0]
するc[0] =1;
と、メモリは次のようになります
01 02 00 00
つまり、リトルエンディアンとしてint
( を実行して) もう一度見ると、10 進数であるprintf("%d",i);
hexです。0x00000201
513
戻って で変更c[1]
するとc[1] =1;
、記憶は次のようになります。
00 01 00 00
ここで戻って、これをリトルエンディアンとして解釈します。これはint
hex0x00000100
で、これは256
10 進数です。
little endian
それがそうであるか、データがビットでどのように格納されているかは、マシンによって異なります。詳細については、エンディアンbig endian
についてこれを読んでください
C 言語はこれを保証しません。
512 in binary :
=============================================
0000 0000 | 0000 0000 | 0000 0010 | 0000 0000 ==>512
=============================================
12 34 56 78
(0x12345678 この int のアドレスを想定)
char *c =(char *)&i now c[0] either point to 0x78 or 0x12
Modifying the value using c[0] may result to 513 if it points to 0x78
=============================================
0000 0000 | 0000 0000 | 0000 0010 | 0000 0001 ==> 513
=============================================
or, can be
=============================================
0000 0001 | 0000 0000 | 0000 0010 | 0000 0000 ==>2^24+512
=============================================
同様に 256 の場合も : c 1は右から 2 バイト目のアドレスを持つためです。下の図で、
=============================================
0000 0000 | 0000 0000 | 0000 0001 | 0000 0000 ==>256
=============================================
したがって、私たちのシステムでの数値表現の実装