5

コンパイラーは、未定義/未指定/実装定義の動作を伴うステートメントに気付いたときに警告することはできませんか(エラーがスローされた場合はさらに良い)?

おそらくステートメントにエラーのフラグを立てるために、標準はそう言うべきですが、少なくともコーダーに警告することができます。そのようなオプションを実装するのに技術的な問題はありますか?それとも単に不可能ですか?

この質問を受け取った理由は、次のようなa[i] = ++i;ステートメントでは、シーケンスポイントに到達する前に、コードが変数を参照し、同じステートメントで変数を変更しようとしていることを認識していないためです。

4

6 に答える 6

8

それはすべて要約すると

  • 実装の品質:警告が正確で有用であればあるほど、それは優れています。すべてのプログラムに対して「このプログラムは未定義動作を呼び出す場合と呼び出さない場合があります」と出力し、それをコンパイルするコンパイラは、かなり役に立たないが、標準に準拠している。ありがたいことに、このようなコンパイラを作成する人は誰もいません:-)。

  • 判別の容易さ:コンパイラーは、未定義の動作、未指定の動作、または実装定義の動作を簡単に判別できない場合があります。5レベルの深さの呼び出しスタックがあり、const char *引数がトップレベルからチェーンの最後の関数に渡され、最後の関数がそれを最初の引数として呼び出すprintf()とします。const char *コンパイラがそれをチェックしconst char *て、それが正しいことを確認しますか?(最初の関数がその値にリテラル文字列を使用すると仮定します。)const char *がファイルから読み取られる場合はどうでしょうか。ただし、ファイルには、出力される値の有効な形式指定子が常に含まれることがわかっていますか?

  • 成功率:コンパイラーは、未定義、未指定などである場合とそうでない場合がある多くの構成を検出できる場合があります。しかし、「成功率」は非常に低いです。その場合、ユーザーは多くの「未定義の可能性がある」メッセージを見たくありません。偽の警告メッセージが多すぎると、実際の警告メッセージが非表示になったり、「低警告」設定でコンパイルするようにユーザーに促したりする可能性があります。それは悪いことです。

あなたの特定の例のために、gcc「未定義かもしれない」についての警告を与えます。printf()フォーマットの不一致についても警告します。

しかし、すべての未定義/未指定のケースに対して診断を発行するコンパイラーが必要な場合、それが機能するかどうかは明確ではありません。

あなたが次のものを持っているとしましょう:

#include <stdio.h>
void add_to(int *a, int *b)
{
    *a = ++*b;
}

int main(void)
{
    int i = 42;
    add_to(&i, &i); /* bad */
    printf("%d\n", i);
    return 0;
}

コンパイラは行について警告する必要があります*a = ++*b;か?

gfがコメントで述べているように、コンパイラは未定義の動作について変換ユニット間でチェックできません。古典的な例は、あるファイルで変数をポインターとして宣言し、別のファイルで配列として定義することです。comp.lang.cFAQ6.1を参照してください。

于 2010-02-20T07:19:27.923 に答える
3

コンパイラが異なれば、条件も異なります。ほとんどのコンパイラには警告レベルのオプションがあり、GCCには特に多くのオプションがありますが、-Wall -Werrorはほとんどの有用なものをオンにし、それらをエラーに強制します。VC ++で同様の保護を行うには、\ W4\WXを使用します。

GCCでは-ansi-pedanticを使用できますが、pedanticはそれが言うことであり、多くの無関係な問題を投げかけ、多くのサードパーティコードを使用することを困難にします。

いずれにせよ、コンパイラーは異なるエラーをキャッチするか、同じエラーに対して異なるメッセージを生成するため、必ずしもデプロイメントではなく、貧乏人の静的分析として複数のコンパイラーを使用すると便利です。Cコードの別のアプローチは、C++としてコンパイルすることです。C ++のより強力な型チェックは、一般的に、より良いCコードをもたらします。ただし、Cコンパイルを機能させる場合は、C++コンパイルのみを使用しないでください。C++固有の機能を導入する可能性があります。繰り返しますが、これはC ++としてデプロイする必要はありませんが、追加のチェックとして使用するだけです。

最後に、コンパイラは通常、パフォーマンスとエラーチェックのバランスをとって構築されています。徹底的にチェックするには、多くの開発者が受け入れない時間がかかります。このため、静的アナライザーが存在します。Cには、従来のリントとオープンソースのスプリントがあります。C ++は静的に分析するのがより複雑であり、ツールはしばしば非常に高価です。私が使用した中で最高のものの1つは、ProgrammingResearchのQAC++です。私は、評判の良い無料またはオープンソースのC++アナライザーを知りません。

于 2010-02-20T09:10:15.673 に答える
2

gccはその状況で警告します(少なくとも-Wall):

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a[5];
  int i = 0;

  a[i] = ++i;

  printf("%d\n", a[0]);

  return 0;
}

与える:

$ make
gcc -Wall main.c -o app
main.c: In function ‘main’:
main.c:8: warning: operation on ‘i’ may be undefined

編集:

なんらかの理由で必要がない場合は、manページをざっと読んでください。-Wsequence-point-Wall

于 2010-02-20T06:58:39.507 に答える
1
于 2010-02-20T07:19:05.530 に答える
0

GCCは、構文的に正しいまま、言語の規範から外れたことを行うと、できる限り警告しますが、特定のポイントを超えると、十分な情報が必要になります。

フラグを指定してGCCを呼び出すと、-Wall詳細を確認できます。

于 2010-02-20T07:03:06.643 に答える
0

コンパイラがこれを警告しない場合は、Linterを試すことができます。

Splintは無料ですが、チェックするのはCのみです http://www.splint.org/

GimpelLintはC++をサポートしていますが、価格は389米ドルです。おそらくあなたの会社はコピーを購入するように説得されるのでしょうか。 http://www.gimpel.com/

于 2010-02-20T09:12:04.657 に答える