sizeof
| 対応: | C89(1989) |
|---|
『sizeof』演算子は、データ型や変数がメモリ上で占めるバイト数を返します。環境依存のサイズをコード内に直接書くことなく、移植性の高いプログラムを書くために活用されます。
構文
// 型のサイズをバイト数で返します。 sizeof(型) // 変数のサイズをバイト数で返します。 sizeof(変数名) sizeof 変数名 // 変数の場合は括弧を省略できます。 // 配列全体のバイト数を返します。 sizeof(配列名) // 配列の要素数を求めるイディオムです。 sizeof(配列名) / sizeof(配列名[0])
主な型のサイズ(64ビット環境の目安)
| 型 | サイズ | 概要 |
|---|---|---|
| char | 1バイト | C言語では『sizeof(char)』は常に1と定義されています。 |
| short | 2バイト | ほぼすべての環境で2バイトです。 |
| int | 4バイト | 多くの環境で4バイトですが、規格では『short以上』と定められています。 |
| long | 4〜8バイト | Windowsの64ビットでは4バイト、Linux/macOSの64ビットでは8バイトです。 |
| long long | 8バイト | C99で追加された型です。64ビット整数を保証します。 |
| float | 4バイト | IEEE 754単精度浮動小数点数です。 |
| double | 8バイト | IEEE 754倍精度浮動小数点数です。 |
| pointer | 4〜8バイト | 32ビット環境では4バイト、64ビット環境では8バイトです。 |
サンプルコード
sample_sizeof.c
#include <stdio.h>
int main(void) {
printf("char: %zu バイト\n", sizeof(char));
printf("short: %zu バイト\n", sizeof(short));
printf("int: %zu バイト\n", sizeof(int));
printf("long: %zu バイト\n", sizeof(long));
printf("long long: %zu バイト\n", sizeof(long long));
printf("float: %zu バイト\n", sizeof(float));
printf("double: %zu バイト\n", sizeof(double));
int n = 42;
double x = 3.14;
printf("変数 n のサイズ: %zu バイト\n", sizeof n);
printf("変数 x のサイズ: %zu バイト\n", sizeof x);
int scores[10];
printf("配列のサイズ: %zu バイト\n", sizeof(scores)); /* 40バイト(10×4)*/
printf("配列の要素数: %zu\n", sizeof(scores) / sizeof(scores[0]));
int *p = &n;
printf("ポインタのサイズ: %zu バイト\n", sizeof(p)); /* 64ビット環境では 8 */
return 0;
}
コンパイルして実行すると次のようになります。
gcc sizeof.c -o sizeof ./sizeof char: 1 バイト short: 2 バイト int: 4 バイト long: 8 バイト long long: 8 バイト float: 4 バイト double: 8 バイト 変数 n のサイズ: 4 バイト 変数 x のサイズ: 8 バイト 配列のサイズ: 40 バイト 配列の要素数: 10 ポインタのサイズ: 8 バイト
構造体のサイズとパディング
構造体のサイズはメンバを単純に足した値より大きいことがあります。アライメント(境界整列)のためコンパイラがパディング(詰め物)を挿入するためです。
sizeof_struct.c
#include <stdio.h>
typedef struct {
char a; /* 1バイト */
int b; /* 4バイト(3バイトのパディングが入ることがある) */
char c; /* 1バイト */
/* 末尾にもパディングが入ることがある */
} WithPadding;
typedef struct {
int b; /* 4バイト */
char a; /* 1バイト */
char c; /* 1バイト */
/* 2バイトのパディング */
} Reordered;
int main(void) {
printf("WithPadding: %zu バイト\n", sizeof(WithPadding));
printf("Reordered: %zu バイト\n", sizeof(Reordered));
return 0;
}
コンパイルして実行すると次のようになります。
gcc sizeof_struct.c -o sizeof_struct ./sizeof_struct WithPadding: 12 バイト Reordered: 8 バイト
よくあるミス
よくあるミス: 関数内で sizeof を使って配列サイズを得ようとする
配列を関数に渡すとポインタに変換されます。関数内で sizeof を使うとポインタのサイズ(8バイトなど)が返り、配列全体のサイズにはなりません。
sizeof_array_ng.c
#include <stdio.h>
void print_size(int arr[]) {
/* NG: ポインタのサイズ(8)が返る */
printf("関数内: %zu バイト\n", sizeof(arr));
}
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
printf("main 内: %zu バイト\n", sizeof(arr)); /* 20 バイト */
print_size(arr);
return 0;
}
修正後は次の通りです。
gcc sizeof_array_ng.c -o sizeof_array_ng ./sizeof_array_ng main 内: 20 バイト 関数内: 8 バイト
sizeof_array_ok.c
#include <stdio.h>
/* OK: 要素数を別引数として渡す */
void print_sum(const int *arr, int n) {
int sum = 0;
for (int i = 0; i < n; i++) sum += arr[i];
printf("合計: %d\n", sum);
}
int main(void) {
int arr[5] = {10, 20, 30, 40, 50};
int n = (int)(sizeof(arr) / sizeof(arr[0]));
print_sum(arr, n); /* 『合計: 150』と出力されます。 */
return 0;
}
修正後は次の通りです。
gcc sizeof_array_ok.c -o sizeof_array_ok ./sizeof_array_ok 合計: 150
概要
『sizeof』はコンパイル時に評価される演算子です(可変長配列に使う場合を除く)。返り値の型は『size_t』という符号なし整数型で、『printf』では『%zu』で出力します。
配列をポインタに代入したり関数に渡したりすると、『sizeof』はポインタ自体のサイズを返します。配列全体のサイズは、配列を直接渡したときのみ正しく取得できます。これは「配列のポインタへの減衰」と呼ばれる挙動です。
動的メモリ確保(『malloc()』)と組み合わせる際は、型のサイズをハードコードせず『sizeof(型)』を使うことで移植性が高まります。構造体のサイズも『sizeof』で取得できますが、アライメント(境界整列)のためパディングが挿入されることがあります。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。