前提
ポインタの勉強をしているのですが、コード内の???に数字を入れ(255,100)と出力させる問題が分からないのでコード内の計算方法と表示の仕方について教えてほしいです。
分からないところ
・*biの計算の仕組み
・ai[3]が296で"("が出力される理由
・%dでの *(short *)((char *)と bi-1,bi-2 の意味
該当のソースコード
C
1#include <stdio.h> 2 3int main(void){ 4 short ai[4] = {???,???,???,296}; 5 short *bi=(short *)((char *)(ai - sizeof(ai) / sizeof(int) +4)+1); 6 7printf("%c",*((char *)&ai[3])); 8printf("%d,",*(short *)((char *)bi-1)); 9printf("%d",*(int *)(bi-2)); 10printf("%c\n",*((char *)ai)); 11 12return 0; 13}
追記
環境はLinuxの64Bitのリトルエンディアンで実行しています
追記2
*biの式を間違えていたため修正しました。
追記3
ソースコードに間違いがあったため修正しました。
もとは何かの課題だと思いますが、質問文中に提示のコードは、オリジナルのものと寸分違わないものですか? また、指定、前提の環境として64ビット版のC言語コンパイラですか? ただ、精査はしていないものの、32ビット版でも64ビット版でも「printf("%d",*(int *)(bi-2));」のコードの「bi-2」が解せません。
環境の前提としては64ビット版のC言語コンパイラです。
また「printf("%d",*(int *)(bi-2));」は誤記ではないです。
> short *bi=(short *)((char *)(ai - sizeof(ai) / sizeof(int) +4)+1);
ああ、質問文中のこの部分を修正したのですね。承知しました。
printf 4 つで、 %c がカッコ、 1 つめの %d が 255 で 2 つめの %d が 100 とすると、 255 と 100 の間の "," はどうやって出すのでしょうね。
> "," はどうやって出すのでしょうね。
ああ、確かにそうですね。課題でしょうし質問、回答、コメントも交錯してますし回答しづらいですね。
その部分も間違えていたため修正しました。何度もすみません。
> その部分も間違えていたため修正しました
責めるつもりはありませんが、前提となる部分に間違いがあると余計な時間が掛かります。
そのために最初に dodox86 さんが「提示のコードは、オリジナルのものと寸分違わないものですか?」と念を押されています。
bi を求める行と最初の printf との間に
printf("ai=%p:", ai);
for(int i=0; i<sizeof(ai); i++) printf(" %02x",*((char*)ai+i)&0xff); printf("\n");
printf("bi=%p\n", bi);
printf("int=%dbyte\n", sizeof(int));
printf("short=%dbyte\n", sizeof(short));
printf("((char *)&ai[3])=%p\n",((char *)&ai[3]));
printf("(short *)((char*)bi-1)=%p\n",(short *)((char *)bi-1));
printf("(int *)(bi-2)=%p\n",(int *)(bi-2));
printf("((char *)ai)=%p\n",((char *)ai));
というのを仕込んで実行したら、どんな表示になるでしょうか。
(配列の ??? は 0 にでもしておいてください。)
全ての???に0を代入して実行した場合下の結果が得られました。
ai=0x7fffacfa0cc0: 00 00 00 00 00 00 28 01
bi=0x7fffacfa0cc5
int=4byte
short=2byte
((char*)&ai[3])=0x7fffacfa0cc6
(short*)((char*)bi-1)=0x7fffacfa0cc4
(int*)(bi-2)=0x7fffacfa0cc1
((char*))ai=0x7fffacfa0cc0
(0,0
ありがとうございます。
64 ビットシステムでも int は 4 バイトなのですね。
この結果で、((char*)&ai[3]) が 0x28 を指していますので、「ai[3]が296で"("が出力される理由」の推測は出来るのではないでしょうか。
また、bi の計算部分はともかく、「%dでの *(short *)((char *)と bi-1,bi-2 の意味」につきましても、実際の値の変化から考えることが出来ると思います。
ただ・・・この結果から、そもそもの「コード内の???に数字を入れ(255,100)と出力させる」というのが出来るように思えません。
int が 4 バイトなら 100 は 64 00 00 00 となり、short が 2 バイトなら 255 は ff 00 です。しかし表示では int のアドレスの最後が short のアドレスの最初と重なっており、つまり short の ff が int の最上位に入ってしまって int が 100 になりません。
表示させるのは実は "(256,100)" だったりはしませんでしょうか。
返信が遅くなりすみません。
表示させるものは"(256,100)"で間違いありません。
ただ説明のおかげで疑問点を理解することができました。
ありがとうございます。
> 表示させるものは"(256,100)"で
ご質問の「前提」には (255,100) と書かれていますが…。
すみません間違えました。
表示させる値は前提の"(255,100)"の方が正しいです。
> 表示させる値は前提の"(255,100)"の方が正しいです。
うーん、気になったので当方でも検証してみたところ、jimbeさんのご指摘のように"(256,100)"は問題が成り立ちましたが、"(255,100)"は成り立ちませんでした。どこか間違っていないか再度確認してみるか、出題者に確認してみた方が良い気がします。
一部、答えを書いてしまうようなんですが、検証したコードです。printfで出力するところにあらかじめ想定する値を投入して出力します。
#include <stdio.h>
#include <assert.h>
int main(void){
assert(sizeof(int) == 4);
//short ai[4] = {???,???,???,296};
short ai[4] = {0, 0, 0, 296};
short *bi=(short *)((char *)(ai - sizeof(ai) / sizeof(int) +4)+1);
// (255,100)
assert(sizeof(ai) == 8);
*((char *)&ai[3]) = '(';
//*(short *)((char *)bi-1) = 255;
*(short *)((char *)bi-1) = 256;
*(int *)(bi-2) = 100;
*((char *)ai) = ')';
printf("%c",*((char *)&ai[3]));
printf("%d,",*(short *)((char *)bi-1));
printf("%d",*(int *)(bi-2));
printf("%c\n",*((char *)ai));
for (int i = 0; i < sizeof(ai) / sizeof(ai[0]); i++) {
// マスクする意味無いので削除 printf("%d, ", ai[i] & 0xffff);
printf("%d, ", ai[i]);
}
printf("\n");
return 0;
}
"(256,100)"なら想定通り。
(256,100)
25641, 0, 256, 296,
"(255,100)"を出力しようとすると、jimbeさんがご指摘のように値が壊れます。
(0,100)
25641, 0, 0, 296,
回答2件
あなたの回答
tips
プレビュー