sizeof が定数で無い件
J http://morihyphen.hp.infoseek.co.jp/log2/200802.html#020813
隣の人がこういうコードを書いててびっくりした。動くらしい。これってC99準拠なんだろうか。
ほへえ。知らなかった。てっきり「コンパイル時定数(こんな言葉あったっけ?)」かと思ってた。
ところで「C99準拠なんだろうか?」と言うのを試してみた。こんなコード。実行環境は Cygwin 。
#include <stdio.h> static int size_print(int size) { int array[size]; printf("array size %d\n", sizeof(array)); } int main(int argc, char *argv[]) { int a = 5; size_print(10); size_print(a); return 0; }
まず「C89」で実行。
isshiki1@isshiki ~/test/sizeof $ gcc -std=c89 -o sizeof sizeof.c isshiki1@isshiki ~/test/sizeof $ ./sizeof array size 40 array size 20 isshiki1@isshiki ~/test/sizeof
ほうほう。まあ期待通りの結果。
続いて「C99」で実行。
isshiki1@isshiki ~/test/sizeof $ gcc -std=c99 -o sizeof sizeof.c isshiki1@isshiki ~/test/sizeof $ ./sizeof array size 40 array size 20 isshiki1@isshiki ~/test/sizeof
同じ結果ですなあ。
思うに、gcc 依存ということは無いでしょうか?他の環境も試さないと何ともいえませんね。
ちょっとディスアセンブラってみよう。結果変わんないから「C89」で。
00401050 <_size_print>: 401050: 55 push %ebp 401051: 89 e5 mov %esp,%ebp 401053: 53 push %ebx 401054: 83 ec 14 sub $0x14,%esp 401057: 89 e3 mov %esp,%ebx 401059: 8b 55 08 mov 0x8(%ebp),%edx 40105c: 89 d0 mov %edx,%eax 40105e: c1 e0 02 shl $0x2,%eax 401061: 83 c0 0f add $0xf,%eax 401064: 83 c0 0f add $0xf,%eax 401067: c1 e8 04 shr $0x4,%eax 40106a: c1 e0 04 shl $0x4,%eax 40106d: 89 45 f8 mov %eax,0xfffffff8(%ebp) 401070: 8b 45 f8 mov 0xfffffff8(%ebp),%eax 401073: e8 78 00 00 00 call 4010f0 <___chkstk> 401078: 89 d0 mov %edx,%eax 40107a: c1 e0 02 shl $0x2,%eax 40107d: 89 44 24 04 mov %eax,0x4(%esp) 401081: c7 04 24 00 20 40 00 movl $0x402000,(%esp) 401088: e8 03 01 00 00 call 401190 <_printf> 40108d: 89 dc mov %ebx,%esp 40108f: 8b 5d fc mov 0xfffffffc(%ebp),%ebx 401092: c9 leave 401093: c3 ret 00401094 <_main>: 401094: 55 push %ebp 401095: 89 e5 mov %esp,%ebp 401097: 83 ec 18 sub $0x18,%esp 40109a: 83 e4 f0 and $0xfffffff0,%esp 40109d: b8 00 00 00 00 mov $0x0,%eax 4010a2: 83 c0 0f add $0xf,%eax 4010a5: 83 c0 0f add $0xf,%eax 4010a8: c1 e8 04 shr $0x4,%eax 4010ab: c1 e0 04 shl $0x4,%eax 4010ae: 89 45 f8 mov %eax,0xfffffff8(%ebp) 4010b1: 8b 45 f8 mov 0xfffffff8(%ebp),%eax 4010b4: e8 37 00 00 00 call 4010f0 <___chkstk> 4010b9: e8 c2 00 00 00 call 401180 <___main> 4010be: c7 45 fc 05 00 00 00 movl $0x5,0xfffffffc(%ebp) 4010c5: c7 04 24 0a 00 00 00 movl $0xa,(%esp) 4010cc: e8 7f ff ff ff call 401050 <_size_print> 4010d1: 8b 45 fc mov 0xfffffffc(%ebp),%eax 4010d4: 89 04 24 mov %eax,(%esp) 4010d7: e8 74 ff ff ff call 401050 <_size_print> 4010dc: b8 00 00 00 00 mov $0x0,%eax 4010e1: c9 leave 4010e2: c3 ret
長いので必要な部分だけ。
ここでこの部分、
4010be: c7 45 fc 05 00 00 00 movl $0x5,0xfffffffc(%ebp) 4010c5: c7 04 24 0a 00 00 00 movl $0xa,(%esp)
ここでまとめて2回分の引数を設定して、
4010cc: e8 7f ff ff ff call 401050 <_size_print>
1回目の呼び出し。ついで、
4010d1: 8b 45 fc mov 0xfffffffc(%ebp),%eax 4010d4: 89 04 24 mov %eax,(%esp) 4010d7: e8 74 ff ff ff call 401050 <_size_print>
2回目の呼び出しで、さっき積んでおいた bp (ベースポインタ)のオフセットから eax に mov してそれをスタックの先頭に書いて呼び出し。
確かに値を実行時に渡してるな。まあそりゃそうか。
んで、sizeof な部分は恐らく、
401057: 89 e3 mov %esp,%ebx 401059: 8b 55 08 mov 0x8(%ebp),%edx 40105c: 89 d0 mov %edx,%eax 40105e: c1 e0 02 shl $0x2,%eax 401061: 83 c0 0f add $0xf,%eax 401064: 83 c0 0f add $0xf,%eax 401067: c1 e8 04 shr $0x4,%eax 40106a: c1 e0 04 shl $0x4,%eax 40106d: 89 45 f8 mov %eax,0xfffffff8(%ebp) 401070: 8b 45 f8 mov 0xfffffff8(%ebp),%eax 401073: e8 78 00 00 00 call 4010f0 <___chkstk> 401078: 89 d0 mov %edx,%eax 40107a: c1 e0 02 shl $0x2,%eax
この辺かしら…?
sizeo に関しては今手元に C 辞典無いから、後で調べてみよう。