| C ユーザーズガイド |
第 6 章
lintソースコード検査プログラムこの章では
lintプログラムの使用方法について説明します。lintプログラムを使用すると実行時にコンパイルエラーや予期しない結果をもたらす可能性のあるコードが C コードにないか検査することができます。多くの場合lintは、コンパイラが必ずしも検出しない誤ったコード、エラーを起こしやすいコード、あるいは標準外コードについて警告を出します。
lintプログラムは C コンパイラにより生成されるすべてのエラーと警告のメッセージを表示します。さらに潜在的バグと移植上の問題に関する警告も表示します。多くの場合、lintから表示されたメッセージは、プログラムのサイズと必要な記憶領域を縮小し、全体の効率を改善する手助けとなります。
lintプログラムはコンパイラと同じロケールを使用し、lintの出力はstderrに送られます。この章の説明項目は次のとおりです。基本
lintと拡張lint基本
lintでも拡張lintでも、ファイル全域 (ライブラリを含む) で矛盾した定義や使用を検出し、ファイルを個別に独立して処理する C コンパイラの不足を補います。特に大きなプロジェクト環境において 1 つの関数が何百ものモジュールで使用される場合、他の方法では探し出すことが困難なバグを発見するのに役立ちます。たとえば、期待しているよりも 1 つ少ない引数で呼び出された関数は、呼び出し時にプッシュされなかった値をスタックから取り出し、そのスタック位置のメモリーの状態によって正しい結果や間違った結果を返します。このような依存性やマシンアーキテクチャへの依存性を検出することにより、lintはユーザー自身のマシンや別のマシンで実行されるコードを確かなものにすることができます。拡張モードでは、
lintは基本モードの場合よりさらに詳しい報告を出します。拡張モードの lint には次の機能が含まれています。拡張モードでは、
lintは次の問題を検出することができます。
- 使用されていない #
include指令、変数、手続き- 解放後のメモリー使用
- 使用されていない割り当て
- 初期化前の変数値の使用
- 割り当てられていないメモリーの解放
- 定数データセグメントへの書き込み時のポインタの使用
- 等しくないマクロの再定義
- 到達しないコード
- 共用体での値の型利用の適合性
- 実際の引数の暗黙の型変換
使用方法
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プログラムは静的アナライザです。そのため、検出した依存性に関する実行時の結果を評価できません。たとえば、あまり重要ではない何百もの到達不可能なbreak文を持ち、これについてユーザーがほとんど何もすることができないプログラムがあるとすると、lintはそれに忠実にフラグを立ててしまいます。この場合、lintのコマンド行オプションと指令 (ソーステキストに埋め込まれた特別の注釈) が役に立ちます。以下にその例を示します。
-bオプションを指定してlintを実行し、到達不可能なbreak文に対するすべての警告を抑制することができます。- 注釈
/* NOTREACHED */を到達不可能な文の前に付けて、その文に対する診断を抑制することができます。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=flint 出力の書式を指定します。f には、macro、simple、src、tab のいずれか 1 つを指定できます。
デフォルトは -errfmt=tab です。-errfmt だけを指定すると、-errfmt=tab を指定するのと同じことになります。
複数の書式を指定すると最後に指定した書式が使用され、lint は使用されない書式について警告を出します。
-errhdr=h
-Ncheckで検査対象になるヘッダーファイルを限定します。h には、<ディレクトリ>、no%<ディレクトリ>、%all、%none、%user の 1 つまたは複数をコンマで区切って指定します。
デフォルトは -errhdr=%none です。-errhdr だけを指定すると、-errhdr=%user を指定するのと同じことになります。以下に例を示します。
%lint -errhdr=inc1 -errhdr=../inc2この例は、ディレクトリ
inc1と../inc2内で使用されているヘッダーファイルを検査します。
%lint -errhdr=%all,no%../incこの例は、ディレクトリ ../inc に入っているものを除く、使用されているすべてのヘッダーファイルを検査します。
-erroff=<タグ>(,<タグ>)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を指定するのと同じことになります。
-errwarn=t指定された警告メッセージが表示された場合、
lintはエラーステータスを返して終了します。t には、<タグ>、no%<タグ>、%all、%noneのいずれかをコンマで区切って指定します。指定する順序は重要です。たとえば、「%all,no%<タグ>」と指定した場合、<タグ> 以外の警告が発行されると、lintは致命的なエラーステータスで終了します。-errwarnの値を以下に示します。
デフォルトは、
-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 つまたは複数をコンマで区切って指定します。
デフォルトは -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=aC++ 形式のコメントを受け入れます。このオプションを使用すると、// を使用してコメントの始まりを示すことができます。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=aK&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を実行することにより、複雑なメッセージを簡単なものに変換することができます。エラーおよび警告メッセージファイルは
/opt/SUNWspro/READMEs/ja 以下のc_lint_messagesにあり、C コンパイラのエラーおよび警告メッセージと lint プログラムメッセージがすべて含まれています。メッセージの多くは読むだけで理解できるようになっています。表示されたメッセージの文字列をテキストファイルから検索すれば、メッセージの説明および多くの場合はコード例を見ることができます。メッセージを抑制するオプション
いくつかの
lintオプションを使用して、lintの診断メッセージを抑制することができます。メッセージを抑制するには、-erroffオプションの後に 1 つ以上の <タグ> を指定して実行してください。これらのニーモニックタグは、-errtags=yesオプションで表示することができます。表 6-6 に
lintのメッセージを抑制するオプションを示します。
lintメッセージの形式lint プログラムに一定のオプションを指定すると、エラーが発生した行位置を示すポインタを伴った詳細なソースファイル行を表示することができます。この機能を使用可能にするオプションは
-errfmt=f です。このオプションを指定しておくと、lintは以下の情報を出力します。たとえば、次に示すプログラム
Test1.cにはエラーがあります。
そこで、次のようなオプションを使用して
Test1.cにlintを実行します。
%lint -errfmt=src-Nlevel=2Test1.c
1 つめの警告は、2 つのコード行の間で矛盾があることを示しています。2 つめの警告には、その時のコールスタックとエラーに到るまでの制御フローが表示されます。
次に示すプログラム
Test2.cには、上記とは異なる種類のエラーがあります。
1 #define AA(b) AR[b+l]2 #define B(c,d) c+AA(d)34 int x=0;56 int AR[10]={1,2,3,4,5,6,77,88,99,0};78 main()9 {10 int y=-5, z=5;11 return B(y,z);12 }
そこで、次のようなオプションを使用して
Test2.cにlintを実行します。
%lint -errfmt=macro 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指令と動作を示します。
lintの参考情報と例
lintが行う検査、lintライブラリ、およびlintフィルタなどに関するlintの参考情報について説明します。
lintが行う検査
lint固有の診断は、矛盾した使い方、移植不能のコード、疑わしい言語構造の 3 つの広い条件カテゴリに対して表示されます。この節では、各カテゴリにおけるlintの動作の例を示し、どのような対応が可能かを説明します。整合性の検査
ファイル全域とファイル内部における変数、引数、関数の矛盾した使用を検査します。概して
lintが古いスタイルの関数に対して検査していたのと同様に、プロトタイプの使用、宣言、引数を検査します。プログラムが関数プロトタイプを使用していない場合、lintは関数の呼び出しごとにコンパイラより厳しく引数の数と型を検査します。lintは、[fs]printf()と[fs]scanf()の制御文字列の変換指示子と引数の不一致も識別します。次に例を示します。
lintはファイル内で呼び出した関数に値を返すことなくそのまま終了してしまうような非void型関数にフラグを立てます。以前、プログラマはfun(){}のように戻り型を省略することによって「関数は値を返さない」ということを示しました。しかし、fun()が戻り型intを持っているとみなすコンパイラには何の意味もありません。この問題を解決するには、戻り型voidの関数として宣言します。lintはファイル全域で非void型関数が値を返さず、しかも式の中でその値が使用されている場合や、これとは反対に関数が返す値が後の呼び出しで時々または常に無視されるという場合を検出します。値が常に無視されるのは、関数定義が不十分だと考えられます。時々無視されるのは、間違ったプログラミングスタイルをとっていることが考えられます (エラー状態のテストが行われていないなど)。strcat()、strcpy()およびsprintf()のような文字列関数や、printf()とputchar()のような出力関数の戻り値を検査する必要がない場合、その問題となる呼び出しはvoid型にキャストしてください。lintは次の場合に変数や関数を識別します。
- したがって、一緒に読み込まれるファイルのすべてにではなくその一部に
lintが適用されると、lintは次の場合に警告を出します。
- そのファイルで宣言された関数と変数が他の場所で定義または使用された。
- そのファイルで使用された関数と変数が他の場所で定義されていた。
- そのファイルで定義された関数と変数が他の場所で使用された。
- a の場合を抑制するには
-xオプションを、b と c の場合を抑制するには-uオプションを使用してください。移植性の検査
lintは、デフォルトでいくつかの移植不能コードを知らせます。lintが-pまたは-Xcを指定して呼び出されると、さらに多くのケースが診断されます。-Xcにより、lintは ANSI/ISO C 規格に一致しない言語構造を検査します。-pと-Xcのもとで発行されるメッセージに関しては、「lint ライブラリ」を参照してください。次に例を示します。
- いくつかの C 言語処理系では、
signedやunsignedと明示的に宣言されない文字変数は、一般に �128 から 127 の範囲の符号付きデータとして扱われます。別の処理系では、これらは一般に 0 から 255 の範囲の負でないデータとして扱われます。そこでEOFが値-1を持つ以下のテストは、文字変数が負でない値を取るマシンでは常に失敗します。
char c;c = getchar();if (c == EOF) ...
-pオプションで呼び出したlintは、普通のcharが負の値を取る可能性があるような比較をすべて検査します。しかし上記の例では、cをsigned charで宣言しても、問題が除去されるのではなく診断が除去されるだけである点に注意してください。これは、getchar()が入力可能な文字と明確なEOF値を返さなければならず、charがその値を格納することができないためです。これは、処理系ごとに定義される符号拡張から生ずる最も一般的な例です。これにより、lintの移植性オプションを注意深く使用すると移植性に関係しないバグを発見するのに役立つということがわかります。ここではcをintで宣言します。
- 同様の問題がビットフィールドにもあります。定数値がビットフィールドに代入される場合、その値を保持するにはフィールドが小さすぎる場合があります。
int型のビットフィールドを符号なしデータとして扱うマシンでは、int x:3に対し許容される値は 0 から 7 の範囲で、符号付きデータとして扱うマシンでは、� 4 から 3 の範囲です。int型を宣言した 3 ビットフィールドは後者のマシンでは値 4 を持つことはできません。-pを指定して呼び出されたlintは、unsigned intまたはsigned int以外のすべてのビットフィールド型にフラグを立てます。unsigned intとsigned intのみが移植可能なビットフィールド型です。コンパイラは、ビットフィールドの型int、char、short、およびlongをサポートしますが、これらはunsigned、signed、またはそのどちらでもない場合があります。さらにコンパイラはenumのビットフィールドの型もサポートします。- 大きなサイズの型が小さなサイズの型に代入されると、バグが発生することがあります。有効なビットが切り捨てられると正確な値を保持できなくなり、
lintは、デフォルトでこの様な代入すべてを知らせます。
short s;long l;s = l;診断は、
-aオプションを指定して呼び出すことにより抑制することができます。どのオプションを指定してlintを呼び出しても、他の診断をも抑制する可能性があることに注意してください。2 つ以上の診断を抑制するオプションについては、「lint ライブラリ」のリストを参照してください。
- あるオブジェクト型へのポインタをより厳密な境界整列要求を持つオブジェクト型のポインタにキャストすると、移植性がなくなることがあります。大部分のマシンでは、
intはcharとは異なり任意のバイト境界から開始することができないため、lintはフラグを立てます。
int *fun(y)char *y;{return(int *)y;}
-hを指定してlintを実行することによってこの診断を抑制することができます。この場合もまた、他のメッセージを抑制する可能性があります。汎用ポインタvoid *を使用すれば他の影響を回避することができます。
- ANSI C は、複雑な式の評価順序を定義していません。この意味は、関数呼び出し、入れ子になった代入文、またはインクリメントとデクリメント演算子から副作用が生じる場合 (すなわち、式評価の副作用として変数が変更される時)、副作用の生じる順序はマシンへの依存度が高いということです。デフォルトでは、
lintは副作用で変更されたり同一式内で他の場所に使用される変数を知らせます。
int a[10];main(){int i = 1;a[i++] = i;}
- この例での
a[1]の値は、あるコンパイラでは1、別のコンパイラでは2という可能性もあります。ビット単位の論理演算子&が論理演算子&&の代わりに誤って使用されると、この診断を引き起こします。
if ((c = getchar()) != EOF & c != '0')疑わしい言語構造
lintは、プログラマの意図には反するが、言語構造上は正しい箇所についても報告します。以下に例を示します。
unsigned x;if (x > 0) ...
if (x != 0) ...
- 最初の例は意図したものではない可能性があります。
lintは、負の定数または0とunsigned変数との疑わしい比較を知らせます。unsigned変数を負数のビットパターンと比較するには、その負数をunsignedにキャストします。
if (u == (unsigned) -1) ...
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を呼び出すと、この診断は抑制されます。
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 つのオプションはフィルタを開発する際に特に役立ちます。
- -s を指定して lint を呼び出すと、複合診断が問題の発生ごとに表示される単純な一行メッセージに変換されます。この解析されたメッセージ書式は awk スクリプトによる分析に適しています。
- -k を指定して lint を呼び出すと、ソースファイルに書き込まれたコメントが出力されるので、プロジェクトの決定を文書化したり後処理の動作を指定するのに便利です。コメントが予想される lint メッセージを示していて、報告されたメッセージがそれと同一であった場合、メッセージは除かれます。-k を使用するときは、
NOTE(LINTED [<メッセージ>])指令をコメントしたいコードの前の行に挿入してください。ここでの <メッセージ> は、lint が -k を指定して呼び出された時に出力されるコメントです。
- /* LINTED [<メッセージ>]*/ のあるファイルに対して -k が使用されない場合の lint の動作については、表 6-7 を参照してください。
|
サン・マイクロシステムズ株式会社 Copyright information. All rights reserved. |
ホーム | 目次 | 前ページへ | 次ページへ | 索引 |