C ユーザーズガイド ホーム目次前ページへ次ページへ索引


第 6 章

lint ソースコード検査プログラム

この章では lint プログラムの使用方法について説明します。lint プログラムを使用すると実行時にコンパイルエラーや予期しない結果をもたらす可能性のあるコードが C コードにないか検査することができます。多くの場合 lint は、コンパイラが必ずしも検出しない誤ったコード、エラーを起こしやすいコード、あるいは標準外コードについて警告を出します。

lint プログラムは C コンパイラにより生成されるすべてのエラーと警告のメッセージを表示します。さらに潜在的バグと移植上の問題に関する警告も表示します。多くの場合、lint から表示されたメッセージは、プログラムのサイズと必要な記憶領域を縮小し、全体の効率を改善する手助けとなります。

lint プログラムはコンパイラと同じロケールを使用し、lint の出力は stderr に送られます。この章の説明項目は次のとおりです。

基本 lint と拡張 lint

lint プログラムは次の 2 つのモードで動作します。

基本 lint でも拡張 lint でも、ファイル全域 (ライブラリを含む) で矛盾した定義や使用を検出し、ファイルを個別に独立して処理する C コンパイラの不足を補います。特に大きなプロジェクト環境において 1 つの関数が何百ものモジュールで使用される場合、他の方法では探し出すことが困難なバグを発見するのに役立ちます。たとえば、期待しているよりも 1 つ少ない引数で呼び出された関数は、呼び出し時にプッシュされなかった値をスタックから取り出し、そのスタック位置のメモリーの状態によって正しい結果や間違った結果を返します。このような依存性やマシンアーキテクチャへの依存性を検出することにより、lint はユーザー自身のマシンや別のマシンで実行されるコードを確かなものにすることができます。

拡張モードでは、lint は基本モードの場合よりさらに詳しい報告を出します。拡張モードの lint には次の機能が含まれています。

拡張モードでは、lint は次の問題を検出することができます。

使用方法

lint プログラムは、コマンド行から起動します。基本モードで lint を起動するには、次のコマンドを使用します。

% lint <ファイル 1>.c <ファイル 2>.c

拡張 lint は、-Nlevel または -Ncheck オプションを使用して、以下のように呼び出します。

% lint -Nlevel=3 <ファイル 1>.c <ファイル 2>.c

lint は、2 つのパスでコードの検査をします。最初のパスでは C ソースファイルに個別のエラー条件を、第 2 のパスでは C ソースファイル間の不整合を検査します。このプロセスは、lint が -c を指定して呼び出されていなければユーザーには見えません。

% lint -c <ファイル 1>.c <ファイル 2>.c

この場合の lint は、最初のパスのみを実行し、第 2 のパスに関連する情報、つまり
<ファイル 1>·c と <ファイル 2>.c 間の定義および使用の矛盾に関する情報を収集します。そして、それを <ファイル 1>·ln および <ファイル 2>.ln と名付けられた中間ファイルとして作成します。

% ls
<ファイル 1>.c 
<ファイル 1>.ln
<ファイル 2>.c
<ファイル 2>.ln

このように、lint の -c オプションは cc の -c オプションがコンパイラのリンク編集段階を抑制するのと同じ様に動作します。一般に、lint のコマンド行構文は cc コマンド行構文に従っています。

.ln ファイルが lint で生成されると、第 2 のパスが実行されます。

% lint <ファイル 1>.ln <ファイル 2>.ln

lint は、そのコマンド行の順番で .c または .ln ファイルをいくつでも処理します。次のコマンド行は、<ファイル 3>.c の内部のエラーと 3 つのファイルすべての整合性を検査するように lint に指令します。

% lint <ファイル 1>.ln <ファイル 2>.ln <ファイル 3>.c

lint は、cc と同じ順序でインクルードヘッダーファイルのディレクトリを検索します。cc の -I オプションを使用するように、lint の -I オプションを使用することができます。詳細については、「インクルードファイル」を参照してください。

lint コマンド行には、複数のオプションを指定することができます。どのオプションも引数を取らず、複数の文字から成るオプションがない場合は、オプション文字を連結して指定することができます。

% lint -cp -I<ディレクトリ 1> -I<ディレクトリ 2> <ファイル 1>.c <ファイル 2>.c

このコマンドは lint に下記のことを指示します。

lint には、特定の処理を実行し、特定の条件について報告するためのオプションが数多くあります。

lint のオプション

lint プログラムは静的アナライザです。そのため、検出した依存性に関する実行時の結果を評価できません。たとえば、あまり重要ではない何百もの到達不可能な break 文を持ち、これについてユーザーがほとんど何もすることができないプログラムがあるとすると、lint はそれに忠実にフラグを立ててしまいます。この場合、lint のコマンド行オプションと指令 (ソーステキストに埋め込まれた特別の注釈) が役に立ちます。以下にその例を示します。

lint のオプションを以下にアルファベット順に説明します。いくつかの lint オプションは、lint 診断メッセージの抑制に関連しています。アルファベット順の説明の後、表 6-6 にこれらのオプションとそれが抑制するメッセージの一覧を示します。拡張 lint を呼び出すオプションは -N で始まります。

lint は、-A、-D、-E、-g、-H、-O、-P、-U、-Xa、-Xc、-Xs、-Xt、-Y を含む多くの cc コマンド行オプションを認識しますが、-g と -O は無視します。認識されないオプションがあると警告が出され、そのオプションは無視されます。

-#

冗長モードをオンにし、呼び出すごとに各構成要素を表示します。

-###

呼び出すごとに各構成要素を表示しますが、実際には実行しません。

-a

一定のメッセージを抑制します。表 6-6 を参照してください。

-b

一定のメッセージを抑制します。表 6-6 を参照してください。

-C<ファイル名>

指定されたファイル名を持った .ln ファイルを作成します。これらの .ln ファイルは、lint の最初のパスだけで作成されます。<ファイル名> は絶対パス名でもかまいません。

-c

コマンド行で指定された .c ファイルごとに、lint の第 2 のパスに関連する情報からなる ·ln ファイルを作成します。第 2 パスは実行されません。

-dirout=<ディレクトリ>

lint 出力ファイル (.ln ファイル) を入れる <ディレクトリ> を指定します。このオプションは -c オプションに影響を与えます。

-err=warn

-err=warn は -errwarn=%all のマクロです。「-errwarn=t」を参照してください。

-errchk=l(, l)

値渡しされた構造体引数 structarg を検査します。ロング整数、およびポインタのサイズが 64 ビットの環境への移植性を検査します。

l には、次に示す 1 つまたは複数の項目をコンマで区切って指定します。

%all

errchk による検査をすべて実行します。

%none

errchk による検査を行いません。これはデフォルトです。

longptr64

ロング整数、およびポインタのサイズが 64 ビットと標準整数のサイズが 32 ビットの環境への移植性を検査します。明示的なキャストが使用されている場合でも、ポインタ式とロング整数式の標準整数への代入を検査します。

no%longptr64

errchk による longptr64 の検査を行いません。
値は、コンマを用いて組み合わせることができます。
-errchk=longptr64,structarg
デフォルトは、-errchk=%none です。-errchk だけを指定すると、
-errchk=%all を指定するのと同じことになります。

no%structarg

errchk による structarg の検査を行いません。

parentheses

コードの保守性を高めます。-errchk=parentheses で警告が返された場合は、さらに括弧を使用して、コード内の演算の優先順位を明確に指示することを検討してください。

signext

このオプションは、符号なし整数型の式における符号付き整数値の符号拡張を、 ANSI/ISO C の通常の値保持規則が認める場合にエラーメッセージを出力します。このオプションは、-errchk=longptr64 が一緒に指定された場合にのみエラーメッセージを出力します。

sizematch

小さな整数に大きな整数が代入された場合に警告を発行します。この警告は、サイズが同じであっても、符号が異なる整数間の代入 (unsigned int = signed int) についても発行されます。

structarg

値渡しされた構造体引数 structarg を検査します。仮引数の型が不明の場合は、その旨が報告されます。

-errchk=locfmtchk

このオプションは lint の最初のパスで printf 形式の文字列を検査する場合に使用します。-errchk=locfmtchk を使用しない場合でも、lint は二度目のパスで必ず printf 形式の文字列を検査します。

-errfmt=f

lint 出力の書式を指定します。f には、macro、simple、src、tab のいずれか 1 つを指定できます。

表 6-1   -errfmt の値
値 意味
macro マクロを展開して、エラーのあるソースコード、行番号、場所を表示します。
simple エラーのある行番号と場所番号 (大括弧内) を表示し、1 行の (簡単な) 診断メッセージを示します。-s オプションと同様ですが、エラー位置に関する情報が入っています。
src エラーのあるソースコード、行番号、場所を表示します。マクロは展開しません。
tab 表形式で表示します。これがデフォルトです。


デフォルトは -errfmt=tab です。-errfmt だけを指定すると、-errfmt=tab を指定するのと同じことになります。

複数の書式を指定すると最後に指定した書式が使用され、lint は使用されない書式について警告を出します。

-errhdr=h

-Ncheck で検査対象になるヘッダーファイルを限定します。h には、<ディレクトリ>、no%<ディレクトリ>、%all、%none、%user の 1 つまたは複数をコンマで区切って指定します。

表 6-2   -errhdr の値
値 意味
<ディレクトリ> <ディレクトリ> で使用されているヘッダーファイルを
検査します。
no%<ディレクトリ> <ディレクトリ> で使用されているヘッダーファイルを
検査しません。
%all 使用されているすべてのヘッダーファイルを検査します。
%none ヘッダーファイルを検査しません。これがデフォルトです。
%user 使用されているすべてのユーザー定義のヘッダーファイルを検査します。すなわち、/usr/include およびそのサブディレクトリに入っているヘッダーファイルとコンパイラが提供しているヘッダーファイルを除く、すべてのヘッダーファイルを検査します。


デフォルトは -errhdr=%none です。-errhdr だけを指定すると、-errhdr=%user を指定するのと同じことになります。以下に例を示します。

% lint -errhdr=inc1 -errhdr=../inc2

この例は、ディレクトリ inc1 と ../inc2 内で使用されているヘッダーファイルを検査します。

% lint -errhdr=%all,no%../inc

この例は、ディレクトリ ../inc に入っているものを除く、使用されているすべてのヘッダーファイルを検査します。

-erroff=<タグ>(,<タグ>)

lint エラーメッセージを抑制または使用可能にします。

t には、<タグ>、no%<タグ>、all、%none の 1 つまたは複数をコンマで区切って指定します。

表 6-3   -erroff の値
値 意味
<タグ> <タグ> で指定したメッセージを抑制します。-errtags=yes オプションで、メッセージのタグを表示することができます。
no%<タグ> <タグ> で指定したメッセージを使用可能にします。
%all すべてのメッセージを抑制します。
%none すべてのメッセージを使用可能にします。これがデフォルトです。


デフォルトは -erroff=%none です。-erroff だけを指定すると、-erroff=%all を指定するのと同じことになります。

% lint -erroff=%all,no%E_ENUM_NEVER_DEF,no%E_STATIC_UNUSED

この例は、「列挙型が定義されていません」と「静的シンボルが使用されていません」のメッセージだけを表示し、その他のメッセージは抑制します。

% lint -erroff=E_ENUM_NEVER_DEF,E_STATIC_UNUSED

この例は、「列挙型が定義されていません」と「静的シンボルが使用されていません」のメッセージだけを抑制します。

-errtags=a

各エラーメッセージのメッセージタグを表示します。a には yes または no のいずれかを指定します。デフォルトは -errtags=no です。-errtags だけを指定すると、
-errtags=yes を指定するのと同じことになります。

すべての -errfmt オプションに使用できます。

-errwarn=t

指定された警告メッセージが表示された場合、lint はエラーステータスを返して終了します。t には、<タグ>、no%<タグ>、%all、%none のいずれかをコンマで区切って指定します。指定する順序は重要です。たとえば、「%all,no%<タグ>」と指定した場合、<タグ> 以外の警告が発行されると、lint は致命的なエラーステータスで終了します。-errwarn の値を以下に示します。

表 6-4   -errwarn の値
tag <タグ> に指定されたメッセージが警告メッセージとして発行された場合、lint は致命的なエラーステータスで終了します。<タグ> が発行されない場合は無効です。
no%tag <タグ> に指定されたメッセージが警告メッセージとしてだけ発行された場合に、lint が致命的なエラーステータスで終了することがないようにします。 <タグ> に指定されたメッセージが発行されない場合は無効です。このオプションは、<タグ> または %all を使用して以前に指定されたメッセージが警告メッセージとして発行されても lint が致命的なエラーステータスで終了しないようにする場合に使用してください。
%all 警告メッセージが何か発行される場合に lint が致命的なエラーステータスで終了するようにします。%all に続いて no%<タグ> を使用すると、警告メッセージによってはこの動作が発生しないように指定できます。
%none どの警告メッセージが発行されても lint が致命的なエラーステータスで終了することがないようにします。


デフォルトは、-errwarn=%none です。-errwarn だけを指定した場合、-errwarn=%all と指定したことと同じになります。

-F

コマンド行で指定された .c ファイルを参照するとき、そのベース名ではなくコマンド行に与えられたパス名を出力します。

-fd

古い形式の関数定義または宣言について報告します。

-flagsrc=<ファイル>

<ファイル> 中に格納されたオプションを用いて lint を実行します。<ファイル> には、1 行に 1 つずつ、複数のオプションを指定できます。

-h

一定のメッセージを抑制します。表 6-6 を参照してください。

-I<ディレクトリ>

インクルード用ヘッダーファイルを <ディレクトリ> から検索します。

-k

/*LINTED[<メッセージ>]*/ 指令または注釈 NOTE(LINTED(<メッセージ>)) の動作を変更します。通常 lint は、上述のような指令の後にコードが続く場合、警告メッセージを抑制します。-k オプションを指定した場合は、指令または注釈の中のコメントを含むメッセージを出力します。

-L<ディレクトリ>

-l と共に使用し、<ディレクトリ> の lint ライブラリを検索します。

-lx

lint ライブラリ llib-lx.ln にアクセスします。

-m

一定のメッセージを抑制します。表 6-6 を参照してください。

-Ncheck=c

ヘッダーファイル中の宣言の対応とマクロの検査を行います。c には、検査項目である macro、extern、%all、%none、no%macro、no%extern の 1 つまたは複数をコンマで区切って指定します。

表 6-5   -Ncheck の値
値 意味
macro ファイル間でのマクロ定義の一貫性を検査します。
extern ソースファイルとそれに関連するヘッダーファイルとの間の宣言の 1 対 1 対応を検査します (たとえば <ファイル 1>.c と
<ファイル 1>.h )。ヘッダーファイルの extern 宣言に余分も不足もないことを確認します。
%all -Ncheck のすべての検査を実行します。
%none -Ncheck の検査を実行しません。これがデフォルトです。
no%macro -Ncheck のマクロ検査を実行しません。
no%extern -Ncheck の extern 検査を実行しません。


デフォルトは -Ncheck=%none です。-Ncheck だけを指定すると、-Ncheck=%all を指定するのと同じことになります。

値はコンマを用いて組み合わせることができます (例 : -Ncheck=extern,macro)。

次に例を示します。

% lint -Ncheck=%all,no%macro

この例はマクロ以外のすべての検査項目を実行します。

-Nlevel=n

問題報告の解析レベルを指定します。このオプションによって、検出するエラーの量を制御することができます。レベルが高いほど検証にかかる時間は長くなります。n は、1、2、3、4 のいずれかの数値です。デフォルトは -Nlevel=2 です。-Nlrevel は -Nlevel=4 と同義になります。

-Nlevel=1

個々の手続きを解析します。いくつかのプログラムの実行パスで発生する無条件エラーを報告します。大域的なデータおよび制御のフロー解析は行いません。

-Nlevel=2

デフォルトです。大域的なデータおよびフローを含め、プログラム全体を解析します。いくつかのプログラムの実行パスで発生する無条件エラーを報告します。

-Nlevel=3

-Nlevel=2 で実行される解析に加えて、定数の伝播、定数が実際の引数として使用されている場合を含め、プログラム全体を解析します。

この解析レベルでの C プログラムの検査は、直前のレベルより 2 倍から 4 倍長い時間がかかります。これは、lint がプログラムの変数に対して取り得る値の集合を作成し、プログラムの部分解釈を行うためです。これらの変数値の集合は、定数と、プログラムで使用可能な定数オペランドを含む条件文に基づいて作成され、他の集合 (定数伝播の形式) を作成するときの基準になります。その後、解析の結果として受け取った集合は、次のアルゴリズムに従って誤りがないか評価されます。

オブジェクトが取り得る値の集合の中に正しい値が存在する場合は、その値が次の伝搬の基準として使用されます。正しい値が存在しない場合は、エラーと診断されます。

-Nlevel=4

-Nlevel=3 で実行される解析に加えて、プログラム全体を解析して一定のプログラム実行パスが使用された場合に発生する条件付きエラーも報告します。

この解析レベルでは、さらに多くの診断メッセージが出力されます。一般的に、この解析アルゴリズムは、不正な値に対してエラーメッセージが生成されることを除けば、-Nlevel=3 の解析アルゴリズムと同じです。このレベルでの解析に要する時間は、2 桁 (約 20 倍から 100 倍) ほど増加する可能性があります。余計にかかる時間は、再帰、条件文などの面でのプログラムの複雑さに比例して長くなります。このため、100,000 行を超えるプログラムに対してこのレベルの解析を行うことはあまり現実的ではありません。

-n

デフォルトの lint 標準 C ライブラリとの互換性検査を抑制します。

-ox

llib-lx.ln という名前の lint ライブラリを作成します。このライブラリは、lint が第 2 パスで使用する .ln ファイルから作成されます。-c オプションを使用すると、すべての -o オプションが無効になります。不要なメッセージを表示しないで lib-lx.ln を作成するには、-x オプションを使用します。lint ライブラリのソースファイルが外部からの参照専用である場合は、-v オプションが便利です。作成された lint ライブラリは、後で lint が -lx で呼び出された場合に使用することができます。

デフォルトでは、ライブラリは lint の基本形式で作成されます。拡張 lint モードを使用した場合は、ライブラリは拡張モードで作成されるため、それ以外のモードでは使用できなくなります。

-p

移植性に関連する一定のメッセージを使用可能にします。

-R<ファイル>

cxref(1) で使用する .ln ファイルを <ファイル> に書き込みます。lint が拡張モードで起動されている場合、このオプションは拡張モードを使用不可能にします。

-s

複合メッセージを単一メッセージに変換します。

-u

一定のメッセージを抑制します。表 6-6 を参照してください。このオプションは、大型プログラムのファイルの一部分に対して lint を実行する場合に適しています。

-V

製品名とリリース時期を標準エラーに書き込みます。

-v

一定のメッセージを抑制します。表 6-6 を参照してください。

-W<ファイル>

cflow(1) で使用する .ln ファイルを <ファイル> に書き込みます。lint が拡張モードで起動されている場合、このオプションは拡張モードを取り消します。

-x

一定のメッセージを抑制します。表 6-6 を参照してください。

-XCC=a

C++ 形式のコメントを受け入れます。このオプションを使用すると、// を使用してコメントの始まりを示すことができます。a には yes または no のいずれかを指定します。
デフォルトは -XCC=no です。-XCC だけを指定すると、-XCC=yes を指定するのと同じことになります。

-Xarch=v9

__sparcv9 マクロを事前に定義して、v9 版の lint ライブラリを検索します。

-Xexplicitpar=a

(SPARC) lint に #pragma MP 指令を認識するよう指定します。a には yes または no のいずれかを指定します。デフォルトは -Xexplicitpar=no です。-Xexplicitpar だけを指定すると、-Xexplicitpar=yes を指定するのと同じことになります。

-Xkeeptmp=a

lint の実行中、一時ファイルを自動的に削除せず、作成した状態のままにします。a には yes または no のいずれかを指定します。デフォルトは -Xkeeptmp=no です。
-Xkeeptmp だけを指定すると、-Xkeeptmp=yes を指定するのと同じことになります。

-Xtemp=<ディレクトリ>

一時ファイルのディレクトリを <ディレクトリ> に設定します。このオプションを指定しないと、一時ファイルは /tmp に格納されます。

-Xtime=a

各 lint パスの実行時間を報告します。a には yes または no のいずれかを指定します。デフォルトは -Xtime=no です。-Xtime だけを指定すると、-Xtime=yes を指定するのと同じことになります。

-Xtransition=a

K&R C と Sun ANSI/ISO C の相違を検出した場合に警告を出します。a には yes または no のいずれかを指定します。デフォルトは -Xtransition=no です。-Xtransition だけを指定すると、-Xtransition=yes を指定するのと同じことになります。

-y

コマンド行で指定されたすべての .c ファイルを、/* LINTLIBRARY */ 指令で開始した場合または注釈 NOTE(LINTLIBRARY) が付いている場合と同じように扱います。lint ライブラリは、通常、/* LINTLIBRARY */ 指令または注釈 NOTE(LINTLIBRARY) を使用して作成します。

lint のメッセージ

大部分の lint のメッセージは簡単な 1 行の文で、問題が起こって診断されるたびに出力されます。インクルードファイルで検出されたエラーはコンパイラでは複数回報告されますが、lint ではそのファイルが他のソースファイルに何度インクルードされようとも一度報告されるだけです。複合メッセージは、ファイル全域の矛盾に対して、また時にはファイル内の問題に対しても表示されます。単一メッセージは、検査しているファイルで問題が発生するごとに知らせます。lint フィルタを使用して (「lint ライブラリ」を参照) 各現象ごとに表示されるメッセージを要求する時に、-s オプションを指定して lint を実行することにより、複雑なメッセージを簡単なものに変換することができます。

lint のメッセージは stderr に書き込まれます。

エラーおよび警告メッセージファイルは /opt/SUNWspro/READMEs/ja 以下のc_lint_messages にあり、C コンパイラのエラーおよび警告メッセージと lint プログラムメッセージがすべて含まれています。メッセージの多くは読むだけで理解できるようになっています。表示されたメッセージの文字列をテキストファイルから検索すれば、メッセージの説明および多くの場合はコード例を見ることができます。

メッセージを抑制するオプション

いくつかの lint オプションを使用して、lint の診断メッセージを抑制することができます。メッセージを抑制するには、-erroff オプションの後に 1 つ以上の <タグ> を指定して実行してください。これらのニーモニックタグは、-errtags=yes オプションで表示することができます。

表 6-6 に lint のメッセージを抑制するオプションを示します。

表 6-6   lint のオプションと抑制されるメッセージ
オプション 抑制されるメッセージ
-a
代入によって暗黙的により小さい型に変換されます
より大きな整数型への変換は符号拡張が不正確になる可能性があります
-b
到達できない文です
-h
等価演算子 "==" の使用が想定される場所に代入演算子 "=" が使用され
ています
演算子 "!"  のオペランドが定数です
case 文を通り抜けます
ポインタのキャストによって境界整列が不正確になる可能性があります
優先度が混乱する可能性があります; 括弧
文が帰結していません: if
文が帰結していません: else
-m
大域的に宣言されていますが静的 (static) にすることができます
-erroff=
<
タグ>
<タグ> で指定した 1 つまたは複数の lint のメッセージ
-u
名前が定義されていますが使用されていません
未定義の名前が使用されています
-v
引数が関数中で使用されていません
-x
名前が宣言されていますが使用も定義もされていません


lint メッセージの形式

lint プログラムに一定のオプションを指定すると、エラーが発生した行位置を示すポインタを伴った詳細なソースファイル行を表示することができます。この機能を使用可能にするオプションは -errfmt=f です。このオプションを指定しておくと、lint は以下の情報を出力します。

たとえば、次に示すプログラム Test1.c にはエラーがあります。

1 #include <string.h>
2 static void cpv(char *s, char* v, unsigned n)
3 { int i;
4   for (i=0; i<=n; i++)
5        *v++ = *s++;
6 }
7 void main(int argc, char* argv[])
8 {
9   if (argc != 0)
10     cpv(argv[0], argc, strlen(argv[0]));
11}


そこで、次のようなオプションを使用して Test1.c に lint を実行します。

% lint -errfmt=src -Nlevel=2 Test1.c 

結果として、次のような出力が得られます。

      |
      |static void cpv(char *s, char* v, unsigned n)
      |            ^  2 行目, Test1.c
      |
      |         cpv(argv[0], argc, strlen(argv[0]));
      |                      ^  10 行目, Test1.c
ポインタ/整数の組み合わせは不適切です: 2 番目の引数
      |
      |static void cpv(char *s, char* v, unsigned n)
      |                               ^  2 行目, Test1.c
      |
      |        cpv(argv[0], argc, strlen(argv[0]));
      |                      ^  10 行目, Test1.c
      |
      |         *v++ = *s++;
      |          ^  5 行目, Test1.c
疑わしい方法で作成されたポインタを使用しています
    v, 定義された場所: Test1.c(2):: Test1.c(5)
    呼び出しスタック:
           main()                ,Test1.c(10)
           cpv()                 ,Test1.c(5)


1 つめの警告は、2 つのコード行の間で矛盾があることを示しています。2 つめの警告には、その時のコールスタックとエラーに到るまでの制御フローが表示されます。

次に示すプログラム Test2.c には、上記とは異なる種類のエラーがあります。

1 #define AA(b) AR[b+l]
2 #define B(c,d) c+AA(d)
3
4 int x=0;
5
6 int AR[10]={1,2,3,4,5,6,77,88,99,0};
7
8 main()
9  {
10  int y=-5, z=5;
11  return B(y,z);
12 }


そこで、次のようなオプションを使用して Test2.c に lint を実行します。

% lint -errfmt=macro Test2.c

結果として、次のような出力が得られます。

      |
      | return B(y,z);
      |        ^  11 行目, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  2 行目, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  1 行目, Test2.c
未定義のシンボル: l
      |
      | return B(y,z);
      |        ^  11 行目, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  2 行目, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  1 行目, Test2.c
変数が設定以前に使用されている可能性があります: l
lint: Test2.c 中のエラー; 出力ファイルは作成されません
lint: 2 回目のパスは実行しません - Test2.c 中のエラー


lint の指令

事前定義された値

次の事前定義はすべてのモードで有効です。

__sun
__unix
__lint
__SUNPRO_C=0x510
__`uname -s`_`uname -r
` (例: __SunOS_5_7)
__RESTRICST (-Xa
および -Xt モードのみ)
__sparc
(SPARC)
__i386 (x86)
__BUILTIN_VA_ARG_INCR
__SVR4
__sparcv9
(-Xarch=v9)

次の事前定義は -Xc モード以外で有効です。

指令

lint 指令を /*...*/ の形式で注釈として表記する方法は、現在サポートされていますが、将来はサポートされなくなる予定です。指令を注釈として挿入する際は、ソースコードの注釈 NOTE(...) として表記することをお勧めします。

以下のようにファイル note.h をインクルードして、lint 指令をソースコードの注釈として指定してください。

 #include <note.h>

lint は、ソースコードの注釈を別のツールと共有します。Sun C コンパイラをインストールすると、/usr/lib/note/SUNW_SPRO-lint ファイルが自動的にインストールされます。このファイルには、locklint が認識する注釈の名前がすべて記述されています。ただし、Sun C のソースコードを検査する lint は、/usr/lib/note と
/OPT/SUNWspro/<現リリース>/note の全ファイルを検索して、該当する注釈を探します。

次のように、環境変数 NOTEPATH を設定することにより、/usr/lib/note 以外の位置を指定することもできます。

setenv NOTEPATH ${NOTEPATH}: <ディレクトリ>

表 6-7 に、lint 指令と動作を示します。

表 6-7   lint 指令と動作  
NOTE(ALIGNMENT(<関数>,n))
n=1, 2, 4, 8,
16, 32, 64, 128
lint に、関数結果を n バイト境界で整列させます。たとえば、malloc() は、char* または void* を返すように定義されていますが、実際にはワードで、また場合によってはダブルワードで整列したポインタを返します。
不正な境界整列に関するメッセージが抑制されます。
NOTE(ARGSUSED(n))
/*ARGSUSEDn*/
指令の次に来る関数に対して、-v オプションのような動作を行います。
以下のメッセージが抑制されます。 指令の後に来る関数定義の最初の n 個以降のすべての引数を対象します。デフォルトは 0 で、必ず n の指定が必要です。

  • 引数が関数中で使用されていません

  • NOTE(ARGUNUSED(<引数>[,
    <引数>...]))
    lint が、指定した引数の使用状況を検査しないようにします (このオプションは、指令の次に来る関数に対してのみ有効です)。
    以下のメッセージが抑制されます。
    NOTE または指令で指定された引数すべてを対象と
    します。
    

  • 引数が関数中で使用されていません

  • NOTE(CONSTCOND)
    /*CONSTCOND*/
    条件式中の定数オペランドに関する警告を抑制します。
    以下のメッセージが抑制されます。 NOTE(CONSTANTCONDITION) または
    /* CONSTANTCONDITION */ も使用できます。
        条件のコンテキストに定数があります
    
        演算子 "!" のオペランドが定数です
    
        論理式が常に偽です: 演算子 "&&"
    
        論理式が常に真です: 演算子 "||" 
    

  • 指令の後に来る言語構造が対象となります。

  • NOTE(EMPTY)
    /*EMPTY*/
    if 文に続く空文の内容に関する警告を抑制しま
    す。この指令は、条件式とセミコロンの間で指定し
    ます。この指令は、有効な else 文を持つ空の if 
    文をサポートするためにあります。また、空の 
    else 文に対するメッセージも抑制します。
    文が帰結していません: if
    (if
    の条件式とセミコロンの間に挿入された場合)
    以下のメッセージが抑制されます。
        文が帰結していません: else 
    
    (else 文とセミコロンの間に挿入された場合)
    
    
     
    
    
    
    NOTE(FALLTHRU)
    /*FALLTHRU*/
    case 文または default ラベルの文までの通り抜けに関する警告を抑制します。
    この指令は、ラベルの直前で指定します。 以下のメッセージが抑制されます。 指令の後に来る case 文が対象となります。
    NOTE(FALLTHROUGH) または
    /* FALLTHROUGH */. も使用できます。
        case 文を通り抜けます
    
    NOTE(LINTED (<メッセージ>))/*LINTED [<メッセージ>]*/ 使用されない変数または関数に関する警告を除く、ファイル内の警告をすべて抑制します。この指令は、lint の警告が表示された行の直前で指定します。
    -k オプションは、lint がこの指令を扱う方法を変更します。lint は、メッセージを抑制する代わりに、コメントに含まれているメッセージがある場合は、そのメッセージを表示します。
    この指令は、lint 実行後にフィルタを行うための
    -s オプションと組み合わせて使用すると便利です。 -k が指定されない場合、指令の後に来るコード行の下記以外のファイル内問題に属するすべての警告を抑制します。
        引数が関数中で使用されていません
    
        宣言がブロック中で使用されていません
    
        変数が関数中で設定されていますが使用されて
    いません
    
        静的シンボルが使用されていません
    
        変数が関数中で使用されていません
    
    <メッセージ> は無視されます。
    NOTE(LINTLIBRARY)
    /*LINTLIBRARY*/
    -o が指定された場合、この指令が先頭に付く .c ファイル中の定義だけをライブラリ ·ln ファイルに書き込みます。ファイル内で使用されない関数および関数の引数に関する内容を抑制します。
    NOTE(NOTREACHED)
    /*NOTREACHED*/
    到達不可コードに関するコメントを適切な時点で停止します。このコメントは、通常、exit(2) などの、関数に対するコールの直後に位置します。
    以下のメッセージが抑制されます。
        到達できない文です
    
    指令の後に来る到達されない文が対象の場合。
    
        case 文を通り抜けます
    指令の後の case 文で、指令の前の case 文から到 達されないものが対象の場合。
        関数が値を返さずに終了しています
    NOTE(PRINTFLIKE(n))
    NOTE(PRINTFLIKE
    (<関 数>,n))/*PRINTFLIKEn*/
    指令の後に来る関数定義の第 n 番目の引数を [fs]printf() の書式文字列として扱い、下記のメッセージを有効にします。残りの引数と変換指示子の間の不整合も対象にします。lint はデフォルトで、標準 C ライブラリで提供される [fs]printf() 関数を呼び出すときのエラーに対してこれらの警告を出します。NOTE 形式の場合は、必ず n を指定します。
        書式文字列が正しくありません
    
        書式から参照される引数が足りません
    
        書式から参照されていない引数があります
    
    NOTE(PROTOLIB(n))
    /*PROTOLIB
    n*/
    n が 1 で NOTE(LINTLIBRARY) または /* LINTLIBRARY */ が使用される場合、この指令が先頭に付く .c ファイルの関数プロトタイプ宣言だけをライブラリ .ln ファイルに書き込みます。デフォルトは処理を取り消す 0 です。NOTE 形式の場合は、必ず n を指定します。
    NOTE(SCANFLIKE(n))
    NOTE(SCANLIKE(<関数>,n))
    /*SCANFLIKEn*/
    関数定義の第 n 番目の引数が [fs]scanf() の書式文字列として扱われること以外は
    NOTE(PRINTFLIKE(n)) または /* PRINTFLIKEn */ と同じです。デフォルトでは、lint は標準 C ライブラリで提供される [fs]scanf() 関数を呼び出すときのエラーに対し警告を出します。NOTE 形式の場合は、必ず n を指定します。
    NOTE(VARARGS(n))
    NOTE(VARARGS(<関数>,n))
    /*VARARGSn*/
    指令の後に来る関数宣言の中の可変数の引数を検査する通常の処理を抑制します。最初の n 個の引数のデータ型を検査します。n が指定されていない場合は、n=0 とみなします。新規のコードを書く場合やコードを更新する場合、末尾には省略記号 (...) を使用することをお勧めします。 この指令の直後で定義されている関数に関しては、以下のメッセージが抑制されます。

  • 可変数の引数で関数が呼び出されています

    n 以上の引数を持つ関数に対する呼び出しを対象にします。NOTE 形式の場合は、必ず n を指定します。
  • lint の参考情報と例

    lint が行う検査、lint ライブラリ、および lint フィルタなどに関する lint の参考情報について説明します。

    lint が行う検査

    lint 固有の診断は、矛盾した使い方、移植不能のコード、疑わしい言語構造の 3 つの広い条件カテゴリに対して表示されます。この節では、各カテゴリにおける lint の動作の例を示し、どのような対応が可能かを説明します。

    整合性の検査

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

    したがって、一緒に読み込まれるファイルのすべてにではなくその一部に lint が適用されると、lint は次の場合に警告を出します。
    1. そのファイルで宣言された関数と変数が他の場所で定義または使用された。
    2. そのファイルで使用された関数と変数が他の場所で定義されていた。
    3. そのファイルで定義された関数と変数が他の場所で使用された。
    a の場合を抑制するには -x オプションを、b と c の場合を抑制するには -u オプションを使用してください。

    移植性の検査

    lint は、デフォルトでいくつかの移植不能コードを知らせます。lint が -p または
    -Xc を指定して呼び出されると、さらに多くのケースが診断されます。-Xc により、lint は ANSI/ISO C 規格に一致しない言語構造を検査します。-p と -Xc のもとで発行されるメッセージに関しては、「lint ライブラリ」を参照してください。次に例を示します。

    -p オプションで呼び出した lint は、普通の char が負の値を取る可能性があるような比較をすべて検査します。しかし上記の例では、c を signed char で宣言しても、問題が除去されるのではなく診断が除去されるだけである点に注意してください。これは、getchar() が入力可能な文字と明確な EOF 値を返さなければならず、char がその値を格納することができないためです。これは、処理系ごとに定義される符号拡張から生ずる最も一般的な例です。これにより、lint の移植性オプションを注意深く使用すると移植性に関係しないバグを発見するのに役立つということがわかります。ここでは c を
    int で宣言します。

    診断は、-a オプションを指定して呼び出すことにより抑制することができます。どのオプションを指定して lint を呼び出しても、他の診断をも抑制する可能性があることに注意してください。2 つ以上の診断を抑制するオプションについては、「lint ライブラリ」のリストを参照してください。

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

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

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

    疑わしい言語構造

    lint は、プログラマの意図には反するが、言語構造上は正しい箇所についても報告します。以下に例を示します。

    一方、次の 2 つのテストは同等です。

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

    if (x != 0) ...
    

    最初の例は意図したものではない可能性があります。lint は、負の定数または 0 と unsigned 変数との疑わしい比較を知らせます。unsigned 変数を負数のビットパターンと比較するには、その負数を unsigned にキャストします。

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

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

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

    ビット単位の演算子 & の優先度は論理演算子 == より低いため、式はユーザーの意図とは異なる次のような式として評価されます。

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

    -h を指定して lint を呼び出すと、この診断は抑制されます。

    lint ライブラリ

    lint ライブラリを使用して、呼び出したライブラリ関数とユーザープログラムとの互換性を検査することができます。関数戻り型の宣言、関数が期待する引数の数と型などを検査します。標準 lint ライブラリは、C 言語処理系で供給されるライブラリに対応し、一般にはシステムの標準位置であるディレクトリに格納されています。慣例では、lint ライブラリは llib-lx.ln という形の名前を持ちます。

    lint 標準 C ライブラリの llib-lc.ln は、デフォルトで lint コマンド行に追加されます。ライブラリ関数との互換性の検査は、-n オプションを指定して呼び出すことにより抑制することができます。その他の lint ライブラリは、-l に対して引数として指定することでアクセスされます。すなわち次のコマンド行は、<ファイル 1>.c と
    <ファイル 2>.c の関数と変数の使用法について、lint ライブラリ llib-lx.ln との互換性を検査するよう lint に指示します。

    % lint -lx <ファイル 1>.c <ファイル 2>.c
    

    定義だけからなるライブラリファイルは、厳密に通常のソースファイルと .ln ファイルとして処理されます。ただしライブラリファイルで関数と変数が矛盾したまま使用されるか、またはライブラリファイルで定義されてもソースファイルでは使用されない関数と変数に対しては警告を出しません。

    自分の lint ライブラリを作成するには、C ソースファイルの先頭に NOTE(LINTLIBRARY) 指令を挿入し、次いで -o オプションとそのライブラリ名を与える -l オプションと共にそのファイルに対して lint を実行してください。

    % lint -ox <ファイル 1>.c <ファイル 2>.c
    

    上記のコマンド行により、NOTE(LINTLIBRARY) が先頭に付いたソースファイル中の定義だけがファイル llib-lx.ln に書き込まれます (lint の -o と cc の -o の類似に注意してください)。ライブラリは、同様に関数プロトタイプ宣言のファイルから作成されます。ただし、NOTE(LINTLIBRARY) と NOTE(PROTOLIB(n)) の両方が宣言ファイルの先頭に挿入されている場合は別です。n が 1 の場合、プロトタイプ宣言は古いスタイルの定義と同様にライブラリ .ln ファイルに書き込まれます。n が デフォルトの 0 の場合、処理はキャンセルされます。-y を指定して lint を呼び出しても、lint ライブラリを作成することができます。

    % lint -y -ox <ファイル 1>.c <ファイル 2>.c
    

    上記のコマンド行で指定された各ソースファイルは NOTE(LINTLIBRARY) で開始したかのように扱われ、その定義だけが llib-lx.ln に書き込まれます。

    デフォルトでは、lint は標準位置で lint ライブラリを検索します。標準位置以外のディレクトリで lint ライブラリを検索するように lint に指示するには、-L オプションを使用してディレクトリのパスを指定します。

    % lint -L<ディレクトリ> -lx <ファイル 1>.c <ファイル 2>.c
    

    拡張モードでは、lint は基本モードで生成される .ln ファイルより多くの情報が格納された .ln ファイルを生成します。拡張モードの lint は、基本モードまたは拡張モードのどちらの lint で生成された .ln ファイルでもすべて読み取って理解することができます。基本モードの lint は、基本モードの lint を用いて生成された .ln ファイルだけを読み取って理解することができます。

    デフォルトでは、lint は /usr/lib ディレクトリのライブラリを使用します。これらのライブラリは基本 lint 形式です。makefile を一度実行して新しい形式の拡張 lint ライブラリを作成すれば、拡張 lint をより効率的に利用することができます。makefile を実行して新しいライブラリを作成するには、次のコマンドを入力してください。

    % cd /opt/SUNWspro/WS6/src/lintlib; make
    

    ここで、/opt/SUNWspro/WS6 はインストールディレクトリです。makefile の実行後、lint は /usr/lib ディレクトリ内のライブラリの代わりに拡張モードの新ライブラリを使うようになります。

    指定されたディレクトリは標準位置の前に検索されます。

    lint フィルタ

    lint フィルタは、プロジェクト固有のポストプロセッサ (後処理) です。典型的な例では awk スクリプトや類似のプログラムを使用して lint の出力を読み取り、ユーザーのプロジェクトが特に問題ないと判断したメッセージを捨てます。たとえば、時々または常に無視される値を返す文字列関数などです。lint オプションと指令だけでは出力に対して十分な制御が与えられない時は、lint フィルタを使用するとカスタマイズされた診断レポートを作成することができます。

    lint の 2 つのオプションはフィルタを開発する際に特に役立ちます。

    /* LINTED [<メッセージ>]*/ のあるファイルに対して -k が使用されない場合の lint の動作については、表 6-7 を参照してください。

    サン・マイクロシステムズ株式会社
    Copyright information. All rights reserved.
    ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引