sizeof演算子のまとめ

sizeof演算子について、いろいろ試してみました。アセンブリコードを見てみると、sizeofオペランドの式はコンパイル時に定数に置換されるか、sizeofの計算に影響を与えない数式の場合、式自体が翻訳時に捨てられているのが分かります。

00000000004004e3 <main>:

int main(int argc, char *argv[]){
  4004e3:	55                   	push   rbp
  4004e4:	48 89 e5             	mov    rbp,rsp
  4004e7:	48 83 ec 30          	sub    rsp,0x30
  4004eb:	89 7d dc             	mov    DWORD PTR [rbp-0x24],edi
  4004ee:	48 89 75 d0          	mov    QWORD PTR [rbp-0x30],rsi
	char	buf[]="ABCDE";
  4004f2:	c7 45 f0 41 42 43 44 	mov    DWORD PTR [rbp-0x10],0x44434241
  4004f9:	66 c7 45 f4 45 00    	mov    WORD PTR [rbp-0xc],0x45
	int		i=0;
  4004ff:	c7 45 f8 00 00 00 00 	mov    DWORD PTR [rbp-0x8],0x0
	int		n=0;
  400506:	c7 45 ec 00 00 00 00 	mov    DWORD PTR [rbp-0x14],0x0
	char	c;

	printf("sizeof(\"\")	= %zu\n", sizeof(""));
  40050d:	b8 18 08 40 00       	mov    eax,0x400818
  400512:	be 01 00 00 00       	mov    esi,0x1
  400517:	48 89 c7             	mov    rdi,rax
  40051a:	b8 00 00 00 00       	mov    eax,0x0
  40051f:	e8 94 fe ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(\"ABCDE\")	= %zu\n", sizeof("ABCDE"));
  400524:	b8 2a 08 40 00       	mov    eax,0x40082a
  400529:	be 06 00 00 00       	mov    esi,0x6
  40052e:	48 89 c7             	mov    rdi,rax
  400531:	b8 00 00 00 00       	mov    eax,0x0
  400536:	e8 7d fe ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(buf)	= %zu\n", sizeof(buf));
  40053b:	b8 41 08 40 00       	mov    eax,0x400841
  400540:	be 06 00 00 00       	mov    esi,0x6
  400545:	48 89 c7             	mov    rdi,rax
  400548:	b8 00 00 00 00       	mov    eax,0x0
  40054d:	e8 66 fe ff ff       	call   4003b8 <printf@plt>
	printf("sizeof('A')	= %zu\n", sizeof('A'));
  400552:	b8 54 08 40 00       	mov    eax,0x400854
  400557:	be 04 00 00 00       	mov    esi,0x4
  40055c:	48 89 c7             	mov    rdi,rax
  40055f:	b8 00 00 00 00       	mov    eax,0x0
  400564:	e8 4f fe ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(node)	= %zu\n", sizeof(node));
  400569:	b8 67 08 40 00       	mov    eax,0x400867
  40056e:	be 08 00 00 00       	mov    esi,0x8
  400573:	48 89 c7             	mov    rdi,rax
  400576:	b8 00 00 00 00       	mov    eax,0x0
  40057b:	e8 38 fe ff ff       	call   4003b8 <printf@plt>

	printf("i = %d\n", i);
  400580:	b8 7b 08 40 00       	mov    eax,0x40087b
  400585:	8b 55 f8             	mov    edx,DWORD PTR [rbp-0x8]
  400588:	89 d6                	mov    esi,edx
  40058a:	48 89 c7             	mov    rdi,rax
  40058d:	b8 00 00 00 00       	mov    eax,0x0
  400592:	e8 21 fe ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(i++)	= %zu\n", sizeof(i++));
  400597:	b8 83 08 40 00       	mov    eax,0x400883
  40059c:	be 04 00 00 00       	mov    esi,0x4
  4005a1:	48 89 c7             	mov    rdi,rax
  4005a4:	b8 00 00 00 00       	mov    eax,0x0
  4005a9:	e8 0a fe ff ff       	call   4003b8 <printf@plt>
	printf("i = %d\n", i);
  4005ae:	b8 7b 08 40 00       	mov    eax,0x40087b
  4005b3:	8b 55 f8             	mov    edx,DWORD PTR [rbp-0x8]
  4005b6:	89 d6                	mov    esi,edx
  4005b8:	48 89 c7             	mov    rdi,rax
  4005bb:	b8 00 00 00 00       	mov    eax,0x0
  4005c0:	e8 f3 fd ff ff       	call   4003b8 <printf@plt>

	printf("n = %d\n", n);
  4005c5:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  4005c8:	b8 96 08 40 00       	mov    eax,0x400896
  4005cd:	89 d6                	mov    esi,edx
  4005cf:	48 89 c7             	mov    rdi,rax
  4005d2:	b8 00 00 00 00       	mov    eax,0x0
  4005d7:	e8 dc fd ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(int [n++]) = %zu\n", sizeof(int [n++]));
  4005dc:	8b 45 ec             	mov    eax,DWORD PTR [rbp-0x14]
  4005df:	89 c2                	mov    edx,eax
  4005e1:	48 63 d2             	movsxd rdx,edx
  4005e4:	48 c1 e2 02          	shl    rdx,0x2
  4005e8:	83 c0 01             	add    eax,0x1
  4005eb:	89 45 ec             	mov    DWORD PTR [rbp-0x14],eax
  4005ee:	b8 9e 08 40 00       	mov    eax,0x40089e
  4005f3:	48 89 d6             	mov    rsi,rdx
  4005f6:	48 89 c7             	mov    rdi,rax
  4005f9:	b8 00 00 00 00       	mov    eax,0x0
  4005fe:	e8 b5 fd ff ff       	call   4003b8 <printf@plt>
	printf("n = %d\n", n);
  400603:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  400606:	b8 96 08 40 00       	mov    eax,0x400896
  40060b:	89 d6                	mov    esi,edx
  40060d:	48 89 c7             	mov    rdi,rax
  400610:	b8 00 00 00 00       	mov    eax,0x0
  400615:	e8 9e fd ff ff       	call   4003b8 <printf@plt>

	printf("n = %d\n", n);
  40061a:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  40061d:	b8 96 08 40 00       	mov    eax,0x400896
  400622:	89 d6                	mov    esi,edx
  400624:	48 89 c7             	mov    rdi,rax
  400627:	b8 00 00 00 00       	mov    eax,0x0
  40062c:	e8 87 fd ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(int [++n]) = %zu\n", sizeof(int [++n]));
  400631:	8b 45 ec             	mov    eax,DWORD PTR [rbp-0x14]
  400634:	83 c0 01             	add    eax,0x1
  400637:	89 45 ec             	mov    DWORD PTR [rbp-0x14],eax
  40063a:	8b 45 ec             	mov    eax,DWORD PTR [rbp-0x14]
  40063d:	48 98                	cdqe
  40063f:	48 8d 14 85 00 00 00 	lea    rdx,[rax*4+0x0]
  400646:	00
  400647:	b8 b7 08 40 00       	mov    eax,0x4008b7
  40064c:	48 89 d6             	mov    rsi,rdx
  40064f:	48 89 c7             	mov    rdi,rax
  400652:	b8 00 00 00 00       	mov    eax,0x0
  400657:	e8 5c fd ff ff       	call   4003b8 <printf@plt>
	printf("n = %d\n", n);
  40065c:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  40065f:	b8 96 08 40 00       	mov    eax,0x400896
  400664:	89 d6                	mov    esi,edx
  400666:	48 89 c7             	mov    rdi,rax
  400669:	b8 00 00 00 00       	mov    eax,0x0
  40066e:	e8 45 fd ff ff       	call   4003b8 <printf@plt>

	printf("sizeof(c)	= %zu\n", sizeof(c));
  400673:	b8 d0 08 40 00       	mov    eax,0x4008d0
  400678:	be 01 00 00 00       	mov    esi,0x1
  40067d:	48 89 c7             	mov    rdi,rax
  400680:	b8 00 00 00 00       	mov    eax,0x0
  400685:	e8 2e fd ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(c+0)	= %zu\n", sizeof(c+0));
  40068a:	b8 e1 08 40 00       	mov    eax,0x4008e1
  40068f:	be 04 00 00 00       	mov    esi,0x4
  400694:	48 89 c7             	mov    rdi,rax
  400697:	b8 00 00 00 00       	mov    eax,0x0
  40069c:	e8 17 fd ff ff       	call   4003b8 <printf@plt>

/*	printf("sizeof(ia)	= %zu\n", sizeof(ia)); */
	printf("sizeof(main)	= %zu\n", sizeof(main));
  4006a1:	b8 f4 08 40 00       	mov    eax,0x4008f4
  4006a6:	be 01 00 00 00       	mov    esi,0x1
  4006ab:	48 89 c7             	mov    rdi,rax
  4006ae:	b8 00 00 00 00       	mov    eax,0x0
  4006b3:	e8 00 fd ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(&main)	= %zu\n", sizeof(&main));
  4006b8:	b8 08 09 40 00       	mov    eax,0x400908
  4006bd:	be 08 00 00 00       	mov    esi,0x8
  4006c2:	48 89 c7             	mov    rdi,rax
  4006c5:	b8 00 00 00 00       	mov    eax,0x0
  4006ca:	e8 e9 fc ff ff       	call   4003b8 <printf@plt>
	printf("n = %d\n", n);
  4006cf:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  4006d2:	b8 96 08 40 00       	mov    eax,0x400896
  4006d7:	89 d6                	mov    esi,edx
  4006d9:	48 89 c7             	mov    rdi,rax
  4006dc:	b8 00 00 00 00       	mov    eax,0x0
  4006e1:	e8 d2 fc ff ff       	call   4003b8 <printf@plt>
	printf("sizeof(func(&n)) = %zu\n", sizeof(func(&n)));
  4006e6:	b8 1d 09 40 00       	mov    eax,0x40091d
  4006eb:	be 04 00 00 00       	mov    esi,0x4
  4006f0:	48 89 c7             	mov    rdi,rax
  4006f3:	b8 00 00 00 00       	mov    eax,0x0
  4006f8:	e8 bb fc ff ff       	call   4003b8 <printf@plt>
	printf("n = %d\n", n);
  4006fd:	8b 55 ec             	mov    edx,DWORD PTR [rbp-0x14]
  400700:	b8 96 08 40 00       	mov    eax,0x400896
  400705:	89 d6                	mov    esi,edx
  400707:	48 89 c7             	mov    rdi,rax
  40070a:	b8 00 00 00 00       	mov    eax,0x0
  40070f:	e8 a4 fc ff ff       	call   4003b8 <printf@plt>

	return 0;
  400714:	b8 00 00 00 00       	mov    eax,0x0
}
  400719:	c9                   	leave
  40071a:	c3                   	ret
  40071b:	90                   	nop
  40071c:	90                   	nop
  40071d:	90                   	nop
  40071e:	90                   	nop
  40071f:	90                   	nop

結果

sizeof("")	= 1
sizeof("ABCDE")	= 6
sizeof(buf)	= 6
sizeof('A')	= 4
sizeof(node)	= 8
i = 0
sizeof(i++)	= 4
i = 0
n = 0
sizeof(int [n++]) = 0
n = 1
n = 1
sizeof(int [++n]) = 8
n = 2
sizeof(c)	= 1
sizeof(c+0)	= 4
sizeof(main)	= 1
sizeof(&main)	= 8
n = 2
sizeof(func(&n)) = 4
n = 2

文字列リテラル・char型配列

sizeof("")      = 1
sizeof("ABCDE") = 6
sizeof(buf)     = 6

文字列リテラルやchar型配列変数というと、式中ではchar型配列における先頭要素へのポインタに展開されますが、sizeof演算子オペランドにおいては、char型配列として評価されます。末尾のナル文字を含めたサイズが返されます。なので空文字列は「1」。

文字定数

sizeof('A')	= 4

sizeof(char)は「1」ですが、文字定数はint型なので「4」。

構造体

  4 typedef struct node_t{
  5     unsigned char f;
  6     int id;
  7 }node_t, node;
sizeof(node)	= 8

上記の場合、境界調整でパディングが入るため、5でなくて「8」です。

sizeofオペランドの式

i = 0
sizeof(i++)       = 4   …(1)
i = 0

n = 0
sizeof(int [n++]) = 0   …(2)
n = 1

n = 1
sizeof(int [++n]) = 8   …(3)
n = 2

C99以前の規格Cではsizeof演算子オペランドには整数定数式を要求しますが、可変長配列が導入されたC99では、sizeofのオペランドに可変長配列が指定された場合、以下の作用があるようです。

sizeofの式に可変長配列型の名前が現れ、その配列の要素数がsizeof式の値に影響する場合、その配列の
要素数式は(副作用も含めて)完全に計算される。配列の要素数がsizeofの結果に影響しない場合、その
要素数式が計算されるかどうかは未定義である。
(「Cリファレンスマニュアル 第5版」p244より)

つまり、オペランドに可変長配列の要素数でない式が指定された場合(1)、その式は評価されません。オペランドが可変長配列の要素数であり、かつsizeof式の値に影響する場合(2)(3)、その式は評価されます。(2)のn++は評価されますが、後置インクリメントであるため、sizeof式の評価後にインクリメントしています。そのため、sizeof式はインクリメント前の値で配列要素数が計算されています。(3)の++nは前置インクリメントであるため、インクリメント後の値で配列要素数が計算されています。

暗黙の型変換

sizeof(c)    = 1  …(1)
sizeof(c+0)   = 4  …(2)

(1)char型変数のsizeofは「1」です。
(2)c+0の場合、リテラル数0がint型であるため、式c+0はint型としてサイズ計算されます。

関数

sizeof(main)    = 1   (1)
sizeof(&main)   = 8   (2)
n = 2
sizeof(func(&n)) = 4   (3)
n = 2

(1)関数名を指定した場合、「1」を返しますが、これはmeaninglessな値だそうです。sizeofで関数へのポインタ値のサイズを取得する場合、「&」をつけます。
(2)検証機は64bit OSであるため、関数へのポインタ値は「8」となります。
(3)関数funcは、ポインタで渡されたnの格納値をインクリメントする定義としていますが、nの値が更新されていないため、関数内の処理は実行されていないようです。