今日の雑記

生きることでいっぱいいっぱい

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 辞典無いから、後で調べてみよう。