コンピュータプログラミングにおいて、未指定動作とは、プログラミング言語の異なる実装によって変化する可能性のある動作のことです。プログラムのソースコードが異なるコンパイラでコンパイルされた場合、または同じコンパイラでも設定が異なる場合、あるいは同じ実行可能ファイルの異なる部分で異なる動作を示す実行可能ファイルを生成する可能性がある場合、そのプログラムは未指定動作を含むと言えます。それぞれの言語標準や仕様では可能な動作の範囲が規定されているかもしれませんが、正確な動作は実装に依存し、プログラムのソースコードを調べても完全には判明しない場合があります。[ 1 ]未指定動作は、結果として得られるプログラムの外部動作には現れないことが多いですが、異なる出力や結果につながる場合があり、移植性の問題を引き起こす可能性があります。
コンパイラがそれぞれのターゲットプラットフォームに最適なコードを生成できるようにするため、プログラミング言語の標準では、特定のソースコード構造に対して特定の動作を必ずしも強制するわけではありません。[ 2 ]すべての可能なプログラムの正確な動作を明示的に定義しないことは、言語仕様のエラーや弱点とはみなされず、そうすることは現実的ではありません。[ 1 ] CおよびC++言語では、このような移植性のない構造は、一般的に実装定義、未指定、未定義の動作の3 つのカテゴリに分類されます。[ 3 ]
未指定動作の正確な定義は様々です。C++ では、「整形式のプログラム構造と正しいデータに対して、実装に依存する動作」と定義されています。[ 4 ] C++ 標準では、可能な動作の範囲が通常提供されることも指摘されています。[ 4 ]実装定義動作とは異なり、実装がその動作を文書化する必要はありません。[ 4 ]同様に、C 標準では、標準が「2 つ以上の可能性を提供し、いずれの場合もどれが選択されるかについて追加の要件を課さない」動作と定義されています。[ 5 ]未指定動作は未定義動作 とは異なります。後者は通常、誤ったプログラム構造またはデータの結果であり、そのような構造の変換または実行には要件が課されません。[ 6 ]
C言語とC++では、実装定義の動作と未定義の動作を区別しています。実装定義の動作については、実装側で特定の動作を選択し、それを文書化する必要があります。C/C++における例としては、整数データ型のサイズが挙げられます。動作の選択は、プログラムの特定の実行環境において、文書化された動作と一貫している必要があります。
多くのプログラミング言語では、完全な式 を構成する部分式の評価順序が指定されていません。この非決定性により、並列処理の利用など、特定のプラットフォームに最適な実装が可能になります。部分式に副作用がある場合、部分式の評価順序によって、完全な式の評価結果が異なる場合があります。[ 1 ]例えば、
a = f ( b ) + g ( b );ここで、fとがg両方ともを変更する場合b、に格納される結果は、またはが最初に評価されるかどうaかによって異なる場合があります。[ 1 ] CおよびC++言語では、これは関数引数にも適用されます。例:[ 2 ]f(b)g(b)
#include <iostream> int f () { std :: cout << "In f \n " ; return 3 ; }int g () { std :: cout << "In g \n " ; return 4 ; }int sum ( int i , int j ) { return i + j ; }int main () { return sum ( f (), g ()); }結果として生成されるプログラムは、2行の出力を不定の順序で書き出す。[ 2 ] Javaなどの他の言語では、オペランドと関数引数の評価順序が明示的に定義されている。[ 7 ]