sizeof演算子

以下について、sizeofでサイズを調べてみます。

  1. 文字リテラル
  2. 空文字
  3. 文字列リテラル
  4. char型配列
  5. int型配列
  6. int型二次元配列
  7. int型二次元配列の最上位次元の先頭要素の間接参照
  8. int型二次元配列の間接参照
  9. char型配列の集合を管理するポインタ配列
  10. char型配列の集合を管理するポインタ配列の先頭要素への間接参照
  11. 構造体
  12. 構造体ポインタ
  13. 構造体の間接参照
  14. 構造体メンバの間接参照
  15. sizeof演算子の評価結果
  1 #include <stdio.h>
  2 
  3 typedef struct NODE{
  4     int     id;
  5     char    name[32];
  6 }NODE;
  7 
  8 int main()
  9 {
 1  1 #include <stdio.h>
  2 
  3 typedef struct NODE_T{
  4     int     id;
  5     char    name[32];
  6 }NODE_T;
  7 
  8 int main()
  9 {
 10     char    carr[] = "ABCDE";
 11     int     iarr[] = {1,2,3,4,5};
 12     int     iarr2d[][5] = {{1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
 13     int     (*iarr2d_p)[3][5] = &iarr2d;
 14     char    *carr_parr[] = {"aaa", "bbb", "ccc"};
 15     NODE_T  node;
 16     NODE_T  *pnode;
 17 
 18     /* 文字リテラル */
 19     printf(" 1: sizeof('A')          = %2d    # 文字リテラル\n", sizeof('A'));
 20     /* 空文字 */
 21     printf(" 2: sizeof(\"\")           = %2d    # 空文字\n", sizeof(""));
 22     /* 文字列リテラル */
 23     printf(" 3: sizeof(\"ABCDE\")      = %2d    # 文字列リテラル\n", sizeof("ABCDE"));
 24     /* char型配列 */
 25     printf(" 4: sizeof(carr)         = %2d    # char型配列\n", sizeof(carr));
 26     /* int型配列 */
 27     printf(" 5: sizeof(iarr)         = %2d    # int型配列\n", sizeof(iarr));
 28     /* int型二次元配列 */
 29     printf(" 6: sizeof(iarr2d)       = %2d    # int型二次元配列\n", sizeof(iarr2d));
 30     /* int型二次元配列の最上位次元の先頭要素への間接参照 */
 31     printf(" 7: sizeof(*iarr2d)      = %2d    # int型二次元配列の最上位次元の先頭要素の間接参照\n", sizeof(*iarr2d));
 32     /* int型二次元配列の間接参照 */
 33     printf(" 8: sizeof(*iarr2d_p)    = %2d    # int型二次元配列の間接参照\n", sizeof(*iarr2d_p));
 34     /* char型配列の集合を管理するポインタ配列 */
 35     printf(" 9: sizeof(carr_parr)    = %2d    # char型配列の集合を管理するポインタ配列\n", sizeof(carr_parr));
 36     /* char型配列の集合を管理するポインタ配列の先頭要素への間接参照 */
 37     printf("10: siizeof(*carr_parr)  = %2d    # char型配列の集合を管理するポインタ配列の先頭要素への間接参照\n",sizeof(*carr_parr));
 38     /* 構造体 */
 39     printf("11: sizeof(node)         = %2d    # 構造体\n", sizeof(node));
 40     /* 構造体へのポインタ */
 41     printf("12: sizeof(pnode)        = %2d    # 構造体ポインタ\n", sizeof(pnode));
 42     /* 構造体への間接参照 */
 43     printf("13: sizeof(*pnode)       = %2d    # 構造体の間接参照\n", sizeof(*pnode));
 44     /* 構造体メンバへの間接参照 */
 45     printf("14: sizeof(pnode->name)  = %2d    # 構造体メンバの間接参照\n", sizeof(pnode->name));
 46     /* sizeof演算子の評価値 */
 47     printf("15: sizeof(sizeof(char)) = %2d    # sizeof演算子の評価結果\n", sizeof(sizeof(char)));
 48 
 49     if(sizeof(char) - 100 < 0)
 50         printf("OK\n");
 51     else
 52         printf("NG\n");
 53 
 54     return 0;
 55 }

結果は、

 1: sizeof('A')          =  4    # 文字リテラル
 2: sizeof("")           =  1    # 空文字
 3: sizeof("ABCDE")      =  6    # 文字列リテラル
 4: sizeof(carr)         =  6    # char型配列
 5: sizeof(iarr)         = 20    # int型配列
 6: sizeof(iarr2d)       = 60    # int型二次元配列
 7: sizeof(*iarr2d)      = 20    # int型二次元配列の最上位次元の先頭要素の間接参照
 8: sizeof(*iarr2d_p)    = 60    # int型二次元配列の間接参照
 9: sizeof(carr_parr)    = 12    # char型配列の集合を管理するポインタ配列
10: siizeof(*carr_parr)  =  4    # char型配列の集合を管理するポインタ配列の先頭要素への間接参照
11: sizeof(node)         = 36    # 構造体
12: sizeof(pnode)        =  4    # 構造体ポインタ
13: sizeof(*pnode)       = 36    # 構造体の間接参照
14: sizeof(pnode->name)  = 32    # 構造体メンバの間接参照
15: sizeof(sizeof(char)) =  4    # sizeof演算子の評価結果
NG
  1. 文字リテラルは、int型なので4バイト。
  2. 文字列リテラルは、末尾にナル文字が付加されるので、6バイト。
  3. 空文字列は1バイト。
  4. 初期値を持つchar型配列は、末尾にナル文字が付加されるので、6バイト。
  5. 初期値を持つint型配列は、char型配列と違ってナル文字は付加されないので、5*4=20バイト。
  6. 3 x 5 x 4 = 60バイト。
  7. 5 x 4 = 20バイト。
  8. 3 x 5 x 4 = 60バイト。
  9. 3 x 4 = 12バイト。
  10. 一要素はint型なので4バイト。
  11. 4 + 32 = 36バイト。
  12. ポインタ値のサイズなので4バイト。
  13. 4 + 32 = 36バイト。
  14. nameは32バイト。
  15. 符号なし整数なので4バイト。

文字リテラルがint型であること、初期値を持つchar型配列は末尾にナル文字が付加される、という点は留意したいです。
また、sizeofそのものの注意点として…

  1. sizeofが返すsize_t型とは、符号なし広義整数型である。「符号なし」のため、
  2. size_t型は符号なしなので、演算時の二項変換などに注意する。例えば、17〜20行目において、「sizeof(char)-100」の評価結果は「-99」となりそうだが、-演算子の左オペランドがunsignedだが右オペランドが100(signed int)であるため、右オペランドはunsignedに型変換され、評価結果はunsignedとなる。そのため、条件<0は、つねに成立しない。
  3. C99以前では、sizeof演算子オペランドは評価されない。例えば、sizeof(i++)において、iはインクリメントしない。ただしC99では可変長配列が導入されたため、sizeofは定数式ではなくなった。