Oracle® Solaris Studio 12.4: C ユーザーガイド

印刷ビューの終了

更新: 2014 年 12 月
 
 

4.6.1 lint が行う診断

矛盾した使用、移植不可能なコード、疑わしい構造という 3 つの広範な条件カテゴリについての lint 固有の診断が発行されます。このセクションでは、これらのそれぞれの領域での lint の動作の例を確認し、それらが発生させる問題に可能な対応を推奨します。

4.6.1.1 整合性の検査

ファイル全域とファイル内部における変数、引数、関数の矛盾した使用を検査します。概して lint が古いスタイルの関数に対して検査していたのと同様に、プロトタイプの使用、宣言、引数を検査します。プログラムが関数プロトタイプを使用していない場合、lint は関数の呼び出しごとにコンパイラより厳しく引数の数と型を検査します。lint は、[fs]printf()[fs]scanf() の制御文字列の変換指示子と引数の不一致も識別します。

例:

  • lint はファイル内で、呼び出し元の関数に値を提供することなく終了する void でない関数に、フラグを設定します。以前、プログラマは fun() {} のように戻り型を省略することによって「関数は値を返さない」ということを示しました。この規約はこのコンパイラにとって意味がなく、fun() が戻り値の型 int を持つとみなします。この問題を解決するには、戻り型 void の関数として宣言します。

  • lint はファイルから、void でない関数が値を戻さないけれどもあたかもそうしたかのように式内で使用されている場合や、関数がときどきまたは常に無視される値を戻すという反対の問題を検出します。値が常に無視される場合は、関数定義内に非効率性が存在している可能性があり、値がときどき無視されることは、不適切なプログラミングスタイル (典型的には、for エラー条件を検査しない) である可能性があります。strcat()strcpy()、および sprintf() のような文字列関数や、printf()putchar() のような出力関数の戻り値を検査する必要がない場合、問題となる呼び出しは void にキャストしてください。

  • lint は、宣言されているけれども定義または使用されていない、使用されているけれども定義されていない、または定義されているけれども使用されていない変数や関数を洗い出します。一緒に読み込まれる一部のしかしすべてではないファイル群に lint が適用されると、次の状況の関数または変数についてエラーメッセージを発行します。

    • それらのファイルで宣言されているけれどもほかの場所で定義または使用されている。

    • それらのファイルで使用されているけれどもほかの場所で定義されている。

    • それらのファイルで定義されているけれどもほかの場所で使用されている。

    1 つめの状況を抑制するには -x オプション、あとの 2 つを抑制するには -u オプションを呼び出してください。

4.6.1.2 移植性の検査

lint のデフォルト動作では一部の移植不可能なコードにフラグが付けられ、-p または -pedantic を指定して lint が呼び出されるとさらにいくつかのケースが診断されます。lint は ISO C 規格に一致しない言語構造を検査します。-p-pedantic を指定した場合に発行されるメッセージについては、lint ライブラリを参照してください。

例:

  • 一部の C 言語の実装では、signed または unsigned のどちらも明示的に宣言されていない文字変数は、符号付き (signed) の量として扱われ、通常は -128 ~ 127 の範囲になります。ほかの実装では、これらは負にならない量として扱われ、通常は 0 ~ 255 の範囲になります。文字変数が負でない値を取るマシンでは、次のテスト (EOF の値が -1) は常に失敗します。

    char c;
    c = getchar();
    if (c == EOF) ...

    -p 付きで呼び出された lint は、単純char が負の値を持つ可能性があることを暗示する比較をすべて検査します。ただし、この例で csigned char として宣言すると、問題ではなく診断が除去されます。getchar() は可能なすべての文字と独自の EOF 値を戻す必要があるため、char には値を格納できません。この例は、処理系ごとに定義される符号拡張から生ずるおそらくもっとも一般的なものですが、lint の移植性オプションを注意深く使用すると移植性に関係しないバグを発見するのに役立つ可能性があることを示しています。ここでは cint で宣言します。

  • 同様の問題がビットフィールドにもあります。定数値がビットフィールドに代入される場合、その値を保持するにはフィールドが小さすぎる場合があります。int 型のビットフィールドを符号なし (unsigned) の量として取り扱うマシンでは、int x:3 の範囲で許可される値が 0 から 7 であるのに対し、符号付き (signed) の量として取り扱うマシンでは -4 から 3 になります。ただし、int 型として宣言された 3 ビットのフィールドは、後者のマシンでは値 4 を保持できません。-p を指定して呼び出された lint は、unsigned int または signed int を除き、すべてのビットフィールドの型にフラグを付けます。これらのみが、移植可能なビットフィールド型です。コンパイラは、ビットフィールドの型 intcharshort、および long をサポートしますが、これらは unsignedsigned またはそのどちらでもない場合があります。さらに enum のビットフィールドの型もサポートします。

  • 大きなサイズの型が小さなサイズの型に代入されると、問題が発生することがあります。有効なビットが切り捨てられると正確な値を保持できなくなります。

    short s;
    long l;
    s = l;

    lint は、デフォルトでこのような代入すべてを知らせます。診断は、-a オプションを指定して呼び出すことにより抑制することができます。どのオプションを指定して lint を呼び出しても、ほかの診断をも抑制する可能性があることに注意してください。2 つ以上の診断を抑制するオプションについては、lint ライブラリにあるリストを参照してください。

  • あるオブジェクト型へのポインタをより厳格な整列要件を持つオブジェクト型へのポインタにキャストすると、移植性が損なわれる可能性があります。大部分のマシンでは、char が任意のバイト境界から開始できるのに対し、int はそうできないため、lint は次の例にフラグを付けます。

    int *fun(y)
    char *y;
    {
        return(int *)y;
    }

    -h を指定して lint を実行することによってこの診断を抑制することができます。この場合もまた、ほかのメッセージを抑制する可能性があります。汎用ポインタ void * を使用すればほかの影響を回避することができます。

  • ISO C は、複雑な式の評価順序を定義していません。この意味は、関数呼び出し、入れ子になった代入文、またはインクリメントとデクリメント演算子から副作用が生じる場合 (すなわち、式評価の副作用として変数が変更される時)、副作用の生じる順序はマシンへの依存度が高いということです。デフォルトでは、lint は副作用で変更された変数と同一式内でほかの場所に使用される変数にフラグを付けます。

    int a[10];
    main()
    {
        int i = 1;
        a[i++] = i;
    }

    この例では、a[1] の値は、あるコンパイラでは 1 になり、別のコンパイラでは 2 になる可能性があります。ビット単位の論理演算子 & を演算子 && の代わりに誤って使用すると、この診断が呼び出されることがあります。論理

    if ((c = getchar()) != EOF & c != ’0’)

4.6.1.3 疑わしい言語構造

lint は、適正であるが、プログラマが意図した内容を表現していない可能性がある構造の集まりにフラグを付けます。例:

  • unsigned 変数は常に負ではない値を持ちます。このため、次のテストは常に失敗します。

    unsigned x;
    if (x < 0) ...

    次のテスト:

    unsigned x;
    if (x > 0) ...

    これは次と同義です。

    if (x != 0) ...

    この結果は意図したアクションではない可能性があります。lint は、unsigned 変数と、負の定数または 0 との疑わしい比較にフラグを付けます。unsigned 変数を負数のビットパターンと比較するには、その負数を unsigned にキャストします。

    if (u == (unsigned) -1) ...

    または、接尾辞 U を使用します。

    if (u == -1U) ...
  • lint は、副作用が予想されるコンテキストで使用される副作用のない式、すなわちプログラマが意図したことを表現していない式にフラグを付けます。代入演算子が予想されるところ、つまり副作用が予想されたところで等価演算子が見つかるときは追加の警告が発行されます。

    int fun()
    {
        int a, b, x, y;
        (a = x) && (b == y);
    }
  • 演算子の優先度を間違って解釈することにより、不正確な結果になる可能性があるため、lint は、論理演算子とビット単位の演算子 (具体的には、&|^<<>>) の両方が混在する式に括弧を入れるように注意を与えます。たとえば、ビット単位 & の優先度は論理 == より低いため、次の式:

    if (x & a == 0) ...

    は次のように評価されます。

    if (x & (a == 0)) ...

    この結果はおそらく、意図されたものではありません。-h を指定して lint を呼び出すと、診断が無効になります。