C/C++ の sizeof は、オペランドの型情報を元に、オペランドの評価結果のサイズをバイト数で返します。評価結果の値がどうなるかは関係ありません。C++ の型には、静的な型と動的な型(ポインタまたは参照が実際に指している多相オブジェクトの型)がありますが、sizeof 演算子は必ず静的な型のサイズを返します。
1998 年に C++ の標準規格が出来た頃までは、sizeof は必ず定数式になると考えて問題ありませんでした。しかし、C99 ではそうはいかないのです。C99 には可変長配列があります。可変長配列は次のように使います。
void func(int n)
{
int array[n];
...
}
この func 関数の中で sizeof array とすればどうなるでしょうか? 意味的に考えて、この sizeof 演算子は sizeof(int) * n に評価されることでしょう。しかし、n は定数式ではなく、func 関数が実際に呼び出されるまで決定できません。
C++ に限れば、現時点では sizeof は必ず定数式になると考えて問題ありませんが、次期規格ではおそらく C99 の仕様が取り入れられるでしょうから、将来的には常に定数式になるとは限らないと考えた方がよさそうです。
実用上の問題としては、C の場合、switch 文のラベルに sizeof を使った式を記述できないことぐらいしか考えられません。C90 では、集成体(配列と構造体)の初期化子には定数式しか含めることができませんでしたが、C99 では、この制約は静的記憶域期間を持つ場合に限られるため、実質的な問題はありません。あと、関数の中で列挙体を定義した場合に、定数式でなければ列挙子の値に使うことができないという問題がありますが、実際に遭遇することはまずないでしょう。
一方、C++ の場合には深刻な問題になるかもしれません。特に、テンプレートメタプログラミングでは、静的な型の判別に sizeof を使うことが多いため、思わぬところでコンパイルエラーが出るかもしれません。もっとも、それはエラーで当然なのですが、設計段階で気付かないと痛い目を見ることもきっとあるでしょう。ちなみに、GCC などの C99 に対応した処理系では、現時点でも C++ の sizeof が常に定数式になるとは限りません。
ところで、GCC のように typeof 演算子が使える処理系では、可変長配列を使った場合には typeof もある意味動的に解決されることになります。次のようなコードで簡単にエラーになってしまうので要注意です。おそらく、こちらは sizeof より罠にはまる確率が高そうです。
template <typename T>
class A
{
};
int n;
int main()
{
int array[n];
A<typeof(array)> a;
return 0;
}
トラックバック
ブックナビゲーション
- 技術情報
- Boost C++ Libraries メモ
- C++と組込み環境
- C++サンプル集
- C++テンプレート集
- C++プログラマのためのC言語入門
- C/C++迷信集
- [迷信] 'A'~'Z' の値は連続している
- [迷信] 0xe-0xe はゼロ
- [迷信] 1 バイトは 8 ビット
- [迷信] 2の累乗による割り算と右シフトは等価
- [迷信] FILE 型は構造体
- [迷信] abs は常に非負の値を返す
- [迷信] argv[0] はプログラム名
- [迷信] char 型は符号付き
- [迷信] double の出力書式は "%lf"
- [迷信] fflush で入力バッファをクリア
- [迷信] free でメモリを開放する
- [迷信] free に NULL を渡すとクラッシュする
- [迷信] gets は単純に fgets に置き換えられる
- [迷信] isalpha 関数の引数は char 型
- [迷信] new に失敗すると NULL が返る。
- [迷信] scanf ではバッファオーバーランを防げない
- [迷信] scanf でキーボードから入力
- [迷信] setjmp マクロの返却値は変数に代入できる
- [迷信] sizeof は定数式
- [迷信] void main(void)
- [迷信] とりあえず memset で初期化
- [迷信] アルゴリズム関数内で関数オブジェクトはコピーされない
- [迷信] オブジェクトの動的生成に失敗するとメモリリークする
- [迷信] コンストラクタから例外を送出してはならない
- [迷信] コンストラクタで自身をゼロクリア
- [迷信] コンパイラはプログラマの心を察してくれる
- [迷信] コンパイルエラーが出るのでアクセス指定子を修正
- [迷信] ソースコード中の即値を全廃せよ
- [迷信] ソースファイルの末尾に }
- [迷信] データ列のソートには qsort 関数を使うべし
- [迷信] プログラムは必ず main から始まる
- [迷信] 一重引用符の中には一文字しか書けない
- [迷信] 今どき int が 16 ビットの処理系なんて無い
- [迷信] 入力データ格納用配列のサイズは BUFSIZ
- [迷信] 割付けたメモリはプログラマが自分で解放しなければならない
- [迷信] 実数型とは浮動小数点型のことである
- [迷信] 引用符で囲んだヘッダ名はカレントディレクトリから探索する
- [迷信] 文字列から整数への変換には atoi
- [迷信] 構造体のタグ名は下線で始める
- [迷信] 構造体はクラスではない
- [迷信] 識別子に使える文字は英数字と下線のみ
- [迷信] 非局所オブジェクトは外部結合
- C言語再入門
- C言語徹底入門
- Drupal メモ
- TOPPERS 情報
- ライブラリ開発入門
- 分割コンパイルをきわめる
- 擬似プロセッサを作る
- 車輪の再発明
- 過去の情報

