CおよびC++における例
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2022/06/11 09:05 UTC 版)
「未定義動作」の記事における「CおよびC++における例」の解説
パスカル・クオックとジョン・レガーによれば、C言語における未定義動作は、大きく次のような種類に分類できる。 spatial memory safety violations (空間メモリ安全性違反) temporal memory safety violations (時間メモリ安全性違反) integer overflow (整数オーバーフロー) strict aliasing violations (厳密なエイリアシング違反) alignment violations (アライメント違反) unsequenced modifications (非逐次的変更) data races (データ競合) loops that neither perform I/O nor terminate (入出力も終了も行わないループ) C言語では、初期化される前に自動変数を使用すると、ゼロ除算、符号付き整数のオーバーフロー、配列の境界違反(バッファオーバーフローを参照)、またはヌルポインタのデリファレンスと同様の未定義動作が発生する。一般に未定義動作は、抽象化された実行マシンを不明な状態にするため、プログラム全体の動作を未定義にしてしまう。 文字列リテラルを変更しようとすると、未定義動作が発生する。 char *p = "wikipedia"; // C言語では許可、C++98/C++03では非推奨、C++11から不正p[0] = 'W'; // 未定義動作 整数をゼロで除算すると、未定義動作が発生する。 int x = 1;return x / 0; // 未定義動作 特定の種類のポインタ操作は、未定義動作を引き起こす可能性がある。 int arr[4] = {0, 1, 2, 3};int *p = arr + 5; // 未定義動作(配列外読み込み)p = 0;int a = *p; // 未定義動作(ヌルポインタのデリファレンス) CおよびC++では、オブジェクトへのポインターの比較(大小比較)は、ポインターが同じオブジェクトのメンバーである、もしくは同じ配列の要素を指している場合にのみ厳密に定義される。 int main(void){ int a = 0; int b = 0; return &a < &b; /* 未定義動作 */} return文に到達することなく値を返す(main()以外の)関数の終わりに到達すると、関数呼び出しの値が呼び出し元によって使用される場合、未定義動作が発生する。 int f(){} /* 未定義動作(関数の返り値が呼び出し元で使用された場合) */ 2つのシーケンスポイント(英語: sequence point)の間でオブジェクトを複数回変更すると、未定義動作が発生する。C++11の時点で、シーケンスポイントに関連して未定義動作を引き起こす要因にはかなりの変更が行われたが、次の例では、CとC++の両方で未定義動作が発生する。 i = i++ + 1; // 未定義動作 2つのシーケンスポイントの間でオブジェクトを変更する場合、格納する値を決定する以外の目的でオブジェクトの値を読み取ることも、未定義動作となる。 a[i] = i++; // 未定義動作printf("%d %d\n", ++n, power(2, n)); // 同様に未定義動作 CとC++では、値のサイズ以上のビット数、あるいは負の数だけビットシフトすると、未定義動作が発生する。 ここで、コンパイラに関係なく最も安全な方法は、シフトするビット数(<<および>>ビット演算子の右オペランド)を常に0からsizeof(value)*CHAR_BIT - 1 までの範囲内にしておくことである。(ここで、valueはビット演算子の左オペランドである) int num = -1;unsigned int val = 1 << num; // 未定義動作(負数によるビットシフト)num = 32; // もしくは31より大きな任意の整数val = 1 << num; // リテラル「1」は32ビット整数型であるため、31ビット以上のビットシフトは未定義動作となるnum = 64; // もしくは63より大きな任意の整数unsigned long long val2 = 1ULL << num; // リテラル「1ULL」は64ビット整数型であるため、63ビット以上のビットシフトは未定義動作となる
※この「CおよびC++における例」の解説は、「未定義動作」の解説の一部です。
「CおよびC++における例」を含む「未定義動作」の記事については、「未定義動作」の概要を参照ください。
- CおよびC における例のページへのリンク