「表明 (プログラミング)」の版間の差分

削除された内容 追加された内容
編集の要約なし
C11に関して追記。
1行目:
{{otheruses||一般的な意味|wikt:表明}}
'''表明'''(ひょうめい、assertion)とは、[[プログラミング言語]]における概念構文の一種ひとつであり、そのプログラムの前提条件を示すのに使われる。'''アサーション'''とも呼ばれる。表明は、プログラムのその箇所で必ず真であるべき式の形式をとる。多くの言語ではそのような前提条件のチェックに表明を使用するが、設計上の判断を文書化するのに使う場合もある。表明が偽となった場合、プログラムに[[バグ]]が潜在していることを示している。これを「表明違反; assertion failure」と呼ぶ。表明を言語構文や標準ライブラリとしてサポートする[[プログラミング言語]]も存在する
 
プログラマは、開発過程で[[ソースコード]]に表明を追加する。[[デバッグ]]を単純化し、問題を早期に検出するためである。表明違反は[[バグ]]を示していることが多いため、表明の実装では問題の元を示すために追加情報を表示するようになっていることが多い(ソースコードのファイル名と行番号、[[スタックトレース]]など)。ほとんどの実装では、そのプログラムの実行が即座に停止する。
 
== 例 ==
例えば、次の疑似コードには2つの表明が含まれている。
 
<source lang="javapascal">
x := 5;
{x > 0}
x := x + 1
{x > 1}
</source>
 
<code>x > 0</code> と <code>x > 1</code> が表明であり、実行時のその時点でいずれも真である。
 
この例では、[[アントニー・ホーア]]が1969年の論文で採用した表明の記法を使っている<ref>[[アントニー・ホーア|C.A.R. Hoare]], [http://lambda-the-ultimate.org/node/1912 An axiomatic basis for computer programming], ''Communications of the ACM'', 1969.</ref>。この記法は主なプログラミング言語では採用されていない。しかし、実行時にチェックされない表明として[[コメント (コンピュータ)|コメント]]にこの記法で書いておくことはできる。例えば[[C言語|C]]/[[C++]]では次のようになる。
 
<source lang="C">
x = 5;
x = x + 1;
//* {x > 1}< */source>
</source><!-- "//" によるコメントが標準化されたのはC99以降。余計な前提条件を記述しないで済むよう、/**/ を使う。 -->
 
コメント内の表明を括弧で囲んでおくことで、他の通常のコメントと区別しやすくなる。
33 ⟶ 37行目:
表明はプログラマが前提条件としていたことがプログラム実装中にも保持され、プログラム実行時でも正しいことを保証するのに使われる。例えば、以下の[[Java]]コードを見てみよう:
<source lang="java">
int total = countNumberOfUsers();
if assert(total % 2 =>= 0); // total must be {non-negative
if (total % 2 == 0) {
// total is even
} else {
// total is odd and non-negative
// assert(total %must 2be ==odd 1);and non-negative
assert(total % 2 == 1);
}
</source>
 
48 ⟶ 53行目:
表明は決して実行されないと見なされている箇所に置かれることもある。例えば、[[C言語|C]]、[[C++]]、Javaのような言語で、<code>switch</code> 文の <code>default</code> 節に表明を置くことがある。プログラマが予期しない状態が発生した場合、実行をそのまま続けるのではなく、エラーを発生させてプログラムを停止させるのである。
 
Javaでは、表明はバージョン 1.4 から言語の一部となった。表明違反は <code>AssertionError</code> を発生させる。Cでは標準[[ヘッダファイル]] <code>assert.h</code> で <code> assert (''assertion'') </code> マクロが定義されており、エラーを表示してプログラムを停止させるようになっているのが一般的である。[[C++]]の標準では <code>cassert</code> というヘッダを必要とするが、ライブラリによってはC言語同様の <code>assert.h</code> が使用可能となっている。
 
表明はメモリの内容を書き換えてしまったり、スレッドの動作タイミングを変えてしまうなどの[[副作用 (プログラム)|副作用]]を持つ危険性がある。表明はプログラム本体への副作用を生じないよう注意深く実装する必要がある。
76 ⟶ 81行目:
<code>(BOOLEAN CONDITION)</code> が偽と評価されると、配列の長さが負になるため、このコードはコンパイルされなくなる。たとえコンパイラが負のサイズの配列を許したとしても、初期値(<code>'!'</code> の部分)を設定しようとした時点で問題に気付くだろう。
 
これを何度も使用するには、配列名がそれぞれ別々でなければならない。{{いつ範囲|date=2017年9月|最近}}のコンパイラにはプリプロセッサに __COUNTER__ というマクロ定義があり、出現の度に増加する数を返すので、それを名前に含めればよい<ref>GNU, "[http://gcc.gnu.org/gcc-4.3/changes.html GCC 4.3 Release Series — Changes, New Features, and Fixes]"</ref>。
 
[[D言語]]は静的表明 <code>static assert</code> をサポートしている<ref>Static assertions in D''http://dlang.org/version.html#StaticAssert''</ref>。また、[[C++]]では[[C++11]]において <code>[[C++11#静的な表明|static_assert]]</code> が導入された。C言語でも[[C11 (C言語)|C11]]規格で <code>_Static_assert</code> が導入された。
 
== 表明の抑止 ==
88 ⟶ 93行目:
表明とエラー処理ルーチンを区別することには意味がある。表明は論理的にありえない状況をチェックするのに使うべきである。もし、「ありえない」ことが起きたとしたら、根本的に何かが間違っていたということである。エラー処理は通常発生しうるエラーを処理する(もちろん、一部の状況はほとんど「ありえない」かもしれない)。表明をあらゆるエラー処理に使用するのは賢明ではない。表明ではエラーからの復旧が考慮されておらず、表明違反は無条件でプログラムを停止させてしまう場合がほとんどである。表明はユーザー向けの[[エラーメッセージ]]も表示しない。
 
エラー処理に表明を使っているC言語の例を以下に示す。
<syntaxhighlight lang="c">
int *ptr = malloc(sizeof(int) * 10);
98 ⟶ 103行目:
表明の引数である式の副作用に依存するという間違いをすることもある。表明は条件の評価(バグがないことの確認)に使われるものであって、全く実行されないこともあることを常に念頭に置いておく必要がある。最終的にプログラムに問題がないと判断すれば表明を抑止する可能性がある。
 
例えば、次のようなC言語のプログラムがあるとする。
<source lang="c">
int *ptr;
assert(ptr = malloc(sizeof(int) * 10)); // malloc() が失敗すると NULL を返す。しかし、この文は -NDEBUG きでコンパイルすると実行されなくなる。
// ptr を使用する。-NODEBUG-NDEBUG 付きでコンパイルすると、この時点で ptr は設定されていないことになる
 
// ptr を使用する。
...
</source>