Twitter で以下のコードが正しく動作するという話題が回ってきてなるほどってなった:
int a[5] = {1, 2, 3, 4, 5};
int i = 0;
for ( i=0; i < 5; i++ ) {
printf("%d", i[a]);
}
Twitter で以下のコードが正しく動作するという話題が回ってきてなるほどってなった:
int a[5] = {1, 2, 3, 4, 5};
int i = 0;
for ( i=0; i < 5; i++ ) {
printf("%d", i[a]);
}
普通は printf("%d", a[i]); と書くと思いますけど、a[i] って a っていう配列の i 番目のデータを取り出す命令で、ここで a はそもそもポインタで a だけ指定すれば先頭アドレスが取得できますし、「先頭アドレス + 差分アドレス」で実際に取り出すデータを選択していると理解すれば、「差分アドレス + 先頭アドレス」でももちろん取り出せるよね、という。
@yakitama %dが受け取る型はどうなるのかなあ、とか考え始めたら昼寝できなくなりましたw double a[]… にしたら数字が期待通りに表示されるのかな?
@zundan まったく説明できないのですが、このコードで正しく動きましたね……
signed long a[5] = {100, 200, 300, 400, 500};
unsigned char i = 0;
for ( i=0; i<5; i++ ) {
printf("%d", i[a]);
}
% ./ai
100200300400500
@zundan double a[5] でも動きますね、こわいw
@yakitama ぎええw なんだか暗黙の型変換がちゃんとしてくれるように頑張ってくれてるふいんきですね
@zundan ですねえ、人間の理解を越えているw
@zundan i はあくまで整数型なので printf("%d", i[a]); にしてみると、受け取ったデータを整数と解釈して異なるデータが表示されましたが、そらそうだわ。アクセス先が合ってるのか間違ってるのかは、さすがに私には分からないw
@yakitama おー、なるほど。整数の場合は幅の違いが見えにくいのかな?依然、aの型によってiの何倍アドレスを足せばいいのかをたぶんコンパイラが頑張って判断してるんですよねー。i[a]もa[i]も*(a+i)として解釈するのかな?
@zundan えぇ、なんとなく直感でそんな感じの動きをしてるように見えますよね、特に片方がポインタ(a)、片方が整数(i)を渡しているので、判断しようとおもえばできそうな気がします。objdump してアセンブラ読んでみたらヒントがあるかもしれませんが、さすがにそこまではちょっと時間がかかっちゃうのでパスしますw
@yakitama gcc -Sしてみたら同じになりましたーw
$ diff -u ai.c ia.c
--- ai.c 2019-01-19 17:00:47.000000000 -1000
+++ ia.c 2019-01-19 17:00:51.000000000 -1000
@@ -5,7 +5,7 @@
double a[5] = {100, 200, 300, 400, 500};
unsigned char i =0;
for ( i=0; i<5; i++ ) {
- printf("%f, ", a[i]);
+ printf("%f, ", i[a]);
}
return 0;
}
$ gcc -S ai.c
$ gcc -S ia.c
$ diff -u ai.S ia.S
@zundan おー、なるほど、ではやっぱりコンパイラがいい感じにしてくれてるんですね!
senooken JP Social is a social network, courtesy of senooken. It runs on GNU social, version 2.0.2-beta0, available under the GNU Affero General Public License.
All senooken JP Social content and data are available under the Creative Commons Attribution 3.0 license.