Sizeof

sizeof演算子とは



主にCとC++において、`sizeof`はデータ型のサイズをバイト単位で取得する単項演算子です。コンパイル時に計算されることが原則で、式や型指定子を引数に取り、そのサイズを返します。組み込みの数値型、列挙型、ポインタ型、そしてユーザー定義の複合データ型(構造体、共用体C++のクラス)など、ほぼ全てのデータ型に対して使用できます。

sizeof演算子の必要性



多くのプログラムにおいて、データ型のサイズを知ることは非常に重要です。特に動的メモリ確保(`malloc`など)では、確保すべきメモリの大きさを正確に把握する必要があります。C/C++では、`char`型のサイズが1バイトと定められている以外、他の型のサイズは処理系に依存します。そのため、`sizeof`演算子を用いて型のサイズを取得する必要があります。

c
int ptr = (int )malloc(sizeof(int) 10); // int型10個分のメモリを確保


上記の例では、`sizeof(int)`を使って`int`型のサイズを取得し、10倍することで、`int`型配列10個分のメモリを確保しています。このように、型のサイズを仮定せずに`sizeof`を使うことで、移植性の高いコードを書くことが可能です。

CとC++での使用方法



`sizeof`演算子は、キーワード`sizeof`の後に変数、式、または括弧でくくった型名を記述して使用します。変数や式の場合、括弧は省略可能です。

c

include



int main() {
int a;
printf("%zu
", sizeof(int)); // 4 (int型のサイズ)
printf("%zu
", sizeof a); // 4 (変数aのサイズ)
printf("%zu
", sizeof(char)); // 1 (char型のサイズ)
return 0;
}


`sizeof`演算子の結果は、実装定義の符号無し整数型である`size_t`型で返されます。負の値になることはありません。
`sizeof`は関数型、ビットフィールド、不完全型に対しては使用できません。また、`size_t`型を出力する際には、`printf`関数の書式指定子として`%zu`を使用します(C99以降)。

配列に対するsizeof



`sizeof`を配列型に適用すると、配列がメモリ上に占める総サイズが返されます。配列のサイズは、要素の型のサイズに要素数を掛けた値となります。例えば、`sizeof(int[8])`は`sizeof(int) 8`と同じです。

配列の要素数を求めるには、`sizeof(array) / sizeof(array[0])`という式を使います。

c
char str[] = "hello";
int len = sizeof(str) / sizeof(str[0]); // lenは6 (null終端文字含む)


C99可変長配列に対して`sizeof`を適用した場合、配列のサイズは実行時に計算され、コンパイル時定数にはなりません。

sizeofと不完全型



`sizeof`演算子は、完全に定義された型(メモリレイアウトが確定した型)にのみ適用可能です。配列の場合は要素数が変数宣言に含まれている必要があり、構造体や共用体の場合はメンバが完全に定義されている必要があります。

例えば、あるファイルで構造体`struct x`のメンバが定義されていない場合、そのファイル内では`sizeof(struct x)`を使用できません。`struct x`を`sizeof`で使用できるようにするには、構造体の完全な定義を記述する必要があります。

構造体メンバのsizeof



構造体やクラスのメンバに対する`sizeof`は、C++03規格まではオブジェクトからメンバにアクセスする式に対して適用する必要がありました。

c++
struct S { int a; };
S s;
sizeof(s.a); // C++03まではこれが必要


C++11以降では、スコープ解決演算子`::`を用いて、メンバの型名に対して直接`sizeof`を適用できます。

c++
sizeof(S::a); // C++11以降ではこれが可能


sizeofの実装



コンパイラは、言語の実装に従い、`sizeof`演算子をデータ型のメモリ上のサイズを返すように実装する必要があります。`sizeof`は原則としてコンパイル時に計算されるため、アセンブリ言語上では単なる即値になります。

構造体のパディング



構造体やクラスのサイズは、アライメントのためにメンバのサイズの合計よりも大きくなることがあります。多くのコンパイラでは、データをワード単位で揃えるため、メンバ間にパディングと呼ばれる隙間が挿入されることがあります。

c
struct mystruct {
char c;
int i;
};
// sizeof(mystruct)は多くの環境で8になる (charの後にパディングが入る)


各プログラミング言語におけるsizeof



D言語


D言語では、すべての型が持つプロパティとして`.sizeof`が用意されています。

.NET Framework/.NET Core


.NET Framework/.NET Coreでは、`Marshal.SizeOf`メソッドでオブジェクトや型のアンマネージサイズを取得できます。ただし、`System.Boolean`型など、一部の型では結果が異なる場合があります。

C++/CLI


C++/CLIの`sizeof`演算子は、ネイティブ型に用いる限りコンパイル時定数となります。しかし、値クラス、ハンドル型、ジェネリック型引数に対して用いる場合はコンパイル時定数でなくなります。参照クラスやインターフェイス型には使用できません。

C#


C#の`sizeof`演算子は、アンマネージ型のサイズをバイト単位で取得します。結果は`int`型となります。特定の組み込み型に対してはコンパイル時定数になりますが、それ以外の型ではコンパイル時定数にはなりません。unsafeモードが必要ですが、C# 2.0以降は組み込み型に対してのみunsafeが不要となりました。

Visual Basic


Visual Basicでは、`Len`関数で変数のサイズを取得できます。文字列の長さを取得する場合にも使われます。

ActiveBasic


ActiveBasicでは、`Len`関数と`SizeOf`関数が用意されています。`Len`は変数または式に、`SizeOf`は型名に適用できます。

まとめ



`sizeof`演算子は、C/C++プログラミングにおいて、データ型のサイズを正確に把握し、移植性の高いコードを書くために不可欠なツールです。その使い方を正しく理解し、活用することで、より安全で効率的なプログラムを作成することができます。

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。