Oracle Solaris Studio 12.2: C ユーザーガイド

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

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

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

lint プログラムはコンパイラと同じロケールを使用し、lint の出力は stderr に送られます。型に基づく別名の明確化を実行する前に、lint を使用してコードをチェックする詳細と例については、「4.6.3 lint フィルタ」を参照してください。

4.1 基本 lint と拡張 lint

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

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

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

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

4.2 lint 使用方法

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


% lint file1.c file2.c

拡張 lint-Nlevel または -Ncheck オプションを使用して呼び出します。たとえば、次のようにして拡張 lint を起動できます。


% lint -Nlevel=3 file1.c file2.c

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


% lint -c file1.c file2.c

この場合の lint は、最初のパスのみを実行し、第 2 のパスに関連する情報、つまり file1.cfile2.c 間の定義および仕様の不一致に関する情報を file1.ln および file2.ln と名づけられた中間ファイルに収集します。


% ls
file1.c
file1.ln
file2.c
file2.ln

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

次のように .ln ファイルに lint を実行します。


% lint file1.ln file2.ln

この場合、第 2 のパスは実行されます。lint は、そのコマンド行の順番で .c または .ln ファイルをいくつでも処理します。次のようなコマンド行があります。


% lint file1.ln file2.ln file3.c

このコマンド行は、file3.c の内部のエラーと 3 つのファイルすべての整合性を検査するように lint に指令します。

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

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


% lint -cp -Idir1 -Idir2 file1.c file2.c

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

lint にはオプションが数多くあります。これらのオプションを使うと、lint で特定の処理を実行し、特定の条件について報告することができます。

4.3 lint のオプション

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

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

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

4.3.1 -#

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

4.3.2 -###

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

4.3.3 -a

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

4.3.4 -b

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

4.3.5 -C filename;

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

4.3.6 -c

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

4.3.7 -dirout=dir

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

4.3.8 -err=warn

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

4.3.9 -errchk=l(, l)

l で指定した検査を実行します。デフォルトは、-errchk=%none です。-errchk を指定すると、-errchk=%all を指定する場合と同様に機能します。l には、次に示す 1 つまたは複数の項目をコンマで区切って指定します。たとえば、-errchk=longptr64,structarg のように指定します。

表 4–1 -errchk のフラグ

値  

意味  

%all

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

%none

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

[no%]locfmtchk

printf のような書式文字列を lint の初回受け渡しで検査します。-errchk=locfmtchk を使用するかどうかに関係なく、lint は常に 2 回目の受け渡しで printf のような書式文字列を検査します。

[no%]longptr64

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

[no%]structarg

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

[no%]parentheses

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

[no%]signext

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

[no%]sizematch

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

4.3.10 -errfmt=f

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

表 4–2 -errfmt のフラグ

値  

意味  

macro

マクロを展開して、エラーのあるソースコード、行番号、場所を表示します。 

simple

エラーのある行番号と場所番号 (大括弧内) を表示し、1 行の (簡単な) 診断メッセージを示します。-s オプションと同様ですが、エラー位置に関する情報が入っています。

src

エラーのあるソースコード、行番号、場所を表示します。マクロは展開しません。 

tab

表形式で表示します。これはデフォルト値です。 

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

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

4.3.11 -errhdr=h

-Ncheck も指定すると、lint でヘッダーファイルの一定のメッセージレポート作成ができます。h には、次の 1 つまたは複数の項目をコンマで区切って指定します。dirno%dir%all%none%user

表 4–3 -errhdr のフラグ

値 

意味  

dir

ディレクトリ dir からインクルードされたヘッダーファイル用の -Ncheck のメッセージを報告します。

no%dir

ディレクトリ dir からインクルードされたヘッダーファイル用の -Ncheck のメッセージを報告しません。

%all

使用されているすべてのヘッダーファイルを検査します。 

%none

ヘッダーファイルを検査しません。これはデフォルト値です。 

%user

使用されているすべてのユーザー定義のヘッダーファイルを検査します。すなわち、/usr/include およびそのサブディレクトリに入っているヘッダーファイルとコンパイラが提供しているヘッダーファイルを除く、すべてのヘッダーファイルを検査します。

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

次に例を示します。


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

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


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

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

4.3.12 -erroff=tag(, tag)

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

t には、次の 1 つまたは複数の項目をコンマで区切って指定します。tagno%tag%all%none

表 4–4 -erroff のフラグ

値 

意味  

tag

tag で指定したメッセージを抑制します。-errtags=yes オプションで、メッセージのタグを表示することができます。

no%tag

tag で指定したメッセージを使用可能にします。

%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

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

4.3.13 -errsecurity=v

-errsecurity オプションを使用して、コードのセキュリティーに問題がないか検査することができます。

v には、次のいずれかを指定します。

表 4–5 -errsecurity のフラグ

値  

意味  

core 

このレベルでは、たいていの場合で安全でない、または検査することの難しいソースコードの構文がないかどうかを検査します。このレベルで行われる検査には次のものがあります。 

  • printf() および scanf() 系の関数での変数書式文字列の使用

  • scanf() 関数における非結合文字列 (%s) 形式の使用

  • 安全な使用法のない関数の使用: gets()cftime()ascftime() creat()

  • O_CREAT と組み合わせた open() の不正使用

    このレベルで警告が生成されるソースコードはバグと考えてください。問題のコードを変更することを推奨します。どんな場合でも、単純明快でより安全な別の方法があります。

standard 

このレベルの検査には、core レベルの検査に加えて、安全かもしれないが、より良い別の方法がある構文の検査があります。新しく作成したコードの検査には、このレベルを推奨します。このレベルで追加される検査には、次のものがあります。 

  • strlcpy() 以外の文字列コピー関数の使用

  • 脆弱な乱数関数の使用

  • 安全でない関数を使った一時ファイルの生成

  • fopen() を使ったファイルの作成

  • シェルを呼び出す関数の使用

    このレベルで警告を生成するソースコードは、新しいコードまたは大幅に修正したコードに書き換えてください。従来のコードに含まれるこうした警告に対処することと、アプリケーションを不安定にするリスクとのバランスを検討してください。

extended 

このレベルでは、core および standard レベルの検査を含む完全な検査が行われます。また、状況によっては安全でない可能性がある構文について、多数の警告が生成されます。このレベルの検査は、コードを見直す際の一助になりますが、許容しうるソースコードが守る必要のある基準と考える必要はありません。このレベルで追加される検査には、次のものがあります。 

  • ループ内での getc() または fgetc() の呼び出し

  • パス名競合になりがちな関数の使用

  • exec() 系の関数の使用

  • stat() とほかの関数との間の競合

    このレベルで警告が生成されるコードを見直して、安全上の潜在的な問題があるかどうかを判定することができます。

%none 

-errsecurity 検査を無効にします。

-errsecurity の値が指定されていない場合は、-errsecurity=%none に設定されます。-errsecurity は指定されているが、引数が指定されていない場合は、-errsecurity=standard に設定されます。

4.3.14 -errtags=a

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

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

4.3.15 -errwarn=t

指定された警告メッセージが表示された場合、lint はエラーステータスを返して終了します。t には、次の 1 つまたは複数の項目をコンマで区切って指定します。tagno%tag%all%none。指定する順序は重要です。たとえば、%all,no%tag と指定した場合、tag 以外の警告が発行されると、lint は致命的なエラーステータスで終了します。-errwarn の値を次に示します。

表 4–6 -errwarn のフラグ

tag

tag に指定されたメッセージが警告メッセージとして発行された場合、lint は致命的なエラーステータスで終了します。tag に指定されたメッセージが発行されない場合は無効です。

no%tag

タグに指定されたメッセージが警告メッセージとしてだけ発行された場合に、lint が致命的なエラーステータスで終了することがないようにします。tag に指定されたメッセージが発行されない場合は無効です。このオプションは、tag または %all を使用して以前に指定されたメッセージが警告メッセージとして発行されても lint が致命的なエラーステータスで終了しないようにする場合に使用してください。

%all

警告メッセージが何か発行される場合に lint が致命的なエラーステータスで終了するようにします。%all に続いて no%tag を使用して、特定の警告メッセージを対象から除外することもできます。

%none

どの警告メッセージが発行されても lint が致命的なエラーステータスで終了することがないようにします。

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

4.3.16 -F

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

4.3.17 -fd

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

4.3.18 -flagsrc=file

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

4.3.19 -h

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

4.3.20 -Idir

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

4.3.21 -k

/* LINTED [メッセージ] */ 指令または注釈 NOTE(LINTED(message)) の動作を変更します。通常 lint は、前述のような指令のあとにコードが続く場合、警告メッセージを抑制します。lint は、メッセージを抑制する代わりに、指令または注釈の中のコメントを含むメッセージを出力します。

4.3.22 -Ldir

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

4.3.23 -lx

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

4.3.24 -m

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

4.3.25 -m32|-m64

分析するプログラムのメモリーモデルを指定します。また、選択したメモリーモデル (32 ビットまたは 64 ビット) に対応する lint ライブラリを検索します。

32 ビット C プログラムの確認には -m32 を使用し、64 ビット C プログラムの確認には -m64 を使用します。

ILP32 メモリーモデル (32 ビット int、long、ポインタデータ型) は 64 ビット対応ではないすべての Solaris プラットフォームおよび Linux プラットフォームのデフォルトです。LP64 メモリーモデル (64 ビット long、ポインタデータ型) は 64 ビット対応の Linux プラットフォームのデフォルトです。-m64 は LP64 モデル対応のプラットフォームでのみ使用できます。

以前のリリースのコンパイラでは、メモリーモデル、ILP32 または LP64 は、-Xarch オプションを選択して指定されていました。Solaris Studio 12 以降のコンパイラでは、このようなことはありません。ほとんどのプラットフォームでは、コマンド行に -m64 を追加するだけで 64 ビットプログラムで lint を実行することができます。

事前定義のマクロについては、この lint オプションの一覧の次の節を参照してください。

4.3.26 -Ncheck=c

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

表 4–7 -Ncheck のフラグ

値 

意味  

macro

ファイル間でのマクロ定義の一貫性を検査します。 

extern

ソースファイルとそれに関連するヘッダーファイルとの間の宣言の 1 対 1 対応を検査します (たとえば file1.cfile1.h)。ヘッダーファイルの extern 宣言に余分も不足もないことを確認します。

%all

-Ncheck のすべての検査を実行します。

%none

-Ncheck の検査を実行しません。これはデフォルト値です。

no%macro

-Ncheck のマクロ検査を実行しません。

no%extern

-Ncheckextern 検査を実行しません。

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

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

次に例を示します。


% lint -Ncheck=%all,no%macro

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

4.3.27 -Nlevel=n

拡張 lint 解析のレベルを指定することによって、問題報告の拡張 lint モードを有効にします。このオプションによって、検出するエラーの量を制御することができます。レベルが高いほど検証にかかる時間は長くなります。n は数値で、1234 のいずれかです。デフォルトはありません。-Nlevel が指定されなかった場合は、lint の基本解析モードが使用されます。引数なしで -Nlevel が指定された場合は、-Nlevel=4 に設定されます。

基本および拡張 lint モードについては、「4.2 lint 使用方法」を参照してください。

4.3.27.1 -Nlevel=1

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

4.3.27.2 -Nlevel=2

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

4.3.27.3 -Nlevel=3

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

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

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

4.3.27.4 -Nlevel=4

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

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

4.3.28 -n

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

4.3.29 -ox

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

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

4.3.30 -p

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

4.3.31 -Rファイル

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

4.3.32 -s

「警告:」または「エラー:」で始まる単一の診断メッセージを生成します。デフォルトでは、lint は複合的な出力を生成するためにいくつかのメッセージをバッファリングします。

4.3.33 -u

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

4.3.34 -V

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

4.3.35 -v

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

4.3.36 -Wfile

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

4.3.37 -XCC=a

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


注 –

-xc99=none を使用する場合のみ、このオプションを指定する必要があります。デフォルトの -xc99=all では、lint は // で指定したコメントを受け入れます。


4.3.38 -Xalias_level[=l ]

l には、 anybasicweaklayoutstrictstdstrong のいずれか 1 つが入ります。各レベルの明確化の詳細については、表 B–13 を参照してください。

-Xalias_level を指定しない場合、フラグのデフォルトは -Xalias_level=any になります。このことは、型に基づく別名解析が行われないことを意味します。-Xalias_level を指定してもレベルを設定しない場合、デフォルトは -Xalias_level=layout になります。

lint を実行する際に、明確化のレベルをコンパイラの実行レベルよりも緩やかに設定してください。明確化のレベルをコンパイルより厳密に設定して lint を実行すると、解釈の困難な結果が生成され、誤解を招く恐れがあります。

明確化の詳細と、明確化を支援するために作成されたプラグマのリストについては、「4.6.3 lint フィルタ」を参照してください。

4.3.39 -Xarch=amd64

(Solaris オペレーティングシステム) 推奨されていません。使用しないでください。「4.3.25 -m32|-m64を参照してください。

4.3.40 -Xarch=v9

(Solaris オペレーティングシステム) 推奨されていません。使用しないでください。「4.3.25 -m32|-m64を参照してください。

4.3.41 -Xc99[= o]

-Xc99 フラグは、C99 規格 (『Programming Language - C (ISO/IEC 9899:1999)』) からの実装機能に対するコンパイラの認識状況を制御します。

o には、次のいずれかを指定します。allnone

-Xc99=none を指定すると、C99 機能に対する認識がオフになります。-Xc99=all を指定すると、サポートされている C99 機能に対する認識がオンになります。

引数を付けずに -Xc99 を発行すると、-Xc99=all と同じ結果になります。


注 –

コンパイラのサポートレベルは、デフォルトでは表 C–6 で説明している C99 の機能になりますが、Solaris が提供する /usr/include の標準ヘッダーファイルは、1999 ISO/IEC C 規格にまだ準拠していません。エラーメッセージが生成される場合は、-Xc99=none を指定して、前述のヘッダー用に 1990 ISO/IEC C 規格を使用してみてください。


4.3.42 -Xkeeptmp=a

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

4.3.43 -Xtemp=dir

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

4.3.44 -Xtime=a

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

4.3.45 -Xtransition=a

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

4.3.46 -Xustr={ascii_utf16_ushort| no}

このオプションは、U"ASCII_文字列" という書式の文字列リテラルについて unsigned short int の配列としての認識を有効にします。デフォルトは -Xustr=no です。このオプションは、コンパイラによる U"ASCII_文字列" という文字列リテラルの認識を無効にします。-Xustr=ascii_utf16_ushort は、コンパイラによる U"ASCII_文字列" の文字列リテラルの認識を有効にします。

4.3.47 -x

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

4.3.48 -y

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

4.4 lint のメッセージ

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

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

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

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

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

表 4–8 メッセージを抑制する lint オプション

オプション 

抑制されるメッセージ  

-a

代入によって暗黙的により小さい型に変換されます

より大きな整数型への変換は符号拡張が不正確になる可能性があります

-b

到達できない文です

-h

等価演算子 "==" の使用が想定される場所に代入演算子 "=" が使用されています

演算子 "!" のオペランドが定数です

case 文を通り抜けます

ポインタのキャストによって境界整列が不正確になる可能性があります

優先度が混乱する可能性があります; 括弧

文が帰結していません: if

文が帰結していません: else

-m

大域的に宣言されていますが静的 (static) にすることができます

-erroff=tag

タグで指定した 1 つまたは複数の lint メッセージ

-u

名前が定義されていますが使用されていません

未定義の名前が使用されています

-v

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

-x

名前が宣言されていますが使用も定義もされていません

4.4.2 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.clint を実行します。


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

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


      |static void cpv(char *s, char* v, unsigned n)
      |            ^  line 2, Test1.c
      |
      |         cpv(argv[0], argc, strlen(argv[0]));
      |                      ^  line 10, Test1.c
warning: improper pointer/integer combination: arg #2
      |
      |static void cpv(char *s, char* v, unsigned n)
      |                               ^  line 2, Test1.c
      |
      |cpv(argv[0], argc, strlen(argv[0]));
      |                       ^ line 10, Test1.c
      |
      |        *v++ = *s++;
      |         ^  line 5, Test1.c
warning:use of a pointer produced in a questionable way
    v defined at Test1.c(2)    ::Test1.c(5)
      call stack:
          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.clint を実行します。


% lint -errfmt=macro Test2.c

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


      | return B(y,z);
      |        ^  line 11, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  line 2, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  line 1, Test2.c
error: undefined symbol: l
|
      |    return B(y,z);
      |           ^  line 11, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  line 2, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  line 1, Test2.c
variable may be used before set: l
lint: errors in Test2.c; no output created
lint: pass2 not run - errors in Test2.c

4.5 lint の指令

4.5.1 事前定義された値

lint を実行すると、lint トークンが事前定義されます。事前定義されたトークンのリストについては、cc(1) のマニュアルページも参照してください。

4.5.2 指令

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

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

#include <note.h>

lint は、ソースコードの注釈を別のツールと共有します。Solaris Studio C コンパイラをインストールすると、/usr/lib/note/SUNW_SPRO-lint ファイルが自動的にインストールされます。このファイルには、LockLint が認識する注釈の名前がすべて記述されています。ただし、Solaris Studio C のソースコードを検査する lint は、/usr/lib/note と Solaris Studio のデフォルトの場所である <install-directory>/prod/lib/note の全ファイルを検索して、該当する注釈を探します。

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


setenv NOTEPATH $NOTEPATH:other_location

次の表に、lint 指令と動作を示します。

表 4–9 lint 指令

指令  

処理  

NOTE(ALIGNMENT(fname,n)) n=1, 2, 4, 8, 16, 32, 64, 128

lint に関数結果を n バイトで整列させます。たとえば、malloc() は、char* または void* を返すように定義されていますが、実際にはワードで、または場合によってはダブルワードで整列したポインタを返します。

不正な境界整列に関するメッセージが抑制されます。 

  • 不正確な境界整列

NOTE(ARGSUSED(n))

/*ARGSUSEDn*/

指令の次に来る関数に対して、-v オプションのような動作を行います。

次のメッセージが抑制されます。指令のあとに来る関数定義の最初の n 個以降のすべての引数を対象します。デフォルトは 0 です。NOTE 形式の場合は、必ず n を指定します。

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

NOTE(ARGUNUSED

(引数[,引数...]))

lint が、指定した引数の使用状況を検査しないようにします (このオプションは、指令の次に来る関数に対してのみ有効です)。

次のメッセージが抑制されます。NOTE または指令で指定された引数すべてを対象とします。

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

NOTE(CONSTCOND)

/*CONSTCOND*/

条件式中の定数オペランドに関する警告を抑制します。次のメッセージが抑制されます。NOTE(CONSTANTCONDITION) または

/* CONSTANTCONDITION */ も使用できます。

条件のコンテキストに定数があります

演算子 "!" のオペランドが定数です

論理式が常に偽です:演算子 "&&"

論理式が常に真です:演算子 "||"

NOTE(EMPTY) /*EMPTY*/

if 文に続く null 文の内容に関する警告を抑制します。この指令は、条件式とセミコロンの間で指定します。この指令は、有効な else 文を持つ空の if 文をサポートするためにあります。また、空の else 文に対するメッセージも抑制します。

次のメッセージが抑制されます (if の条件式とセミコロンの間に挿入された場合)。

  • 文が帰結していません: else

    (else 文とセミコロンの間に挿入された場合)

  • 文が帰結していません: if

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(fun_name,n))

/*PRINTFLIKEn*/

指令のあとに来る関数定義の第 n 番目の引数を [fs]printf() の書式文字列として扱い、後述のメッセージを有効にします。残りの引数と変換指示子の間の不整合も対象にします。lint はデフォルトで、標準 C ライブラリで提供される [fs]printf() 関数を呼び出すときのエラーに対してこれらの警告を出します。

NOTE 形式の場合は、必ず n を指定します。

  • 書式文字列が正しくありません

    書式から参照される引数が足りません。書式から参照されていない引数があります

  • 書式から参照される引数が足りません

  • 書式から参照される引数が多すぎます

NOTE(PROTOLIB(n))

/*PROTOLIBn*/

n が 1 で NOTE(LINTLIBRARY) または /* LINTLIBRARY */ が使用される場合、この指令が先頭に付く .c ファイルの関数プロトタイプ宣言だけをライブラリ .ln に書き込みます。デフォルトは処理を取り消す 0 です。

NOTE 形式の場合は、必ず n を指定します。

NOTE(SCANFLIKE(n))

NOTE(SCANLIKE(fun_name,n))

/*SCANFLIKEn*/

関数定義の第 n 番目の引数が [fs]scanf() の書式文字列として扱われること以外は NOTE(PRINTFLIKE(n)) または /* PRINTFLIKEn */ と同じです。デフォルトでは、lint は標準 C ライブラリで提供される [fs]scanf() 関数を呼び出すときのエラーに対し警告を出します。

NOTE 形式の場合は、必ず n を指定します。

NOTE(VARARGS(n))

NOTE(VARARGS(fun_name,n))

/*VARARGSn*/

指令のあとに来る関数宣言の中の可変数の引数を検査する通常の処理を抑制します。最初の n 個の引数のデータ型を検査します。n が指定されていない場合は、n= 0 とみなします。新規のコードを書く場合やコードを更新する場合、定義の中で末尾に省略記号 (...) を使用することを推奨します。

この指令の直後で定義されている関数に関しては、次のメッセージが抑制されます。n 以上の引数を持つ関数に対する呼び出しを対象にします。NOTE 形式の場合は、必ず n を指定します。

  • functions called with variable number of arguments

4.6 lint の参考情報と例

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

4.6.1 lint が行う診断

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

4.6.1.1 整合性の検査

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

次に例を示します。

4.6.1.2 移植性の検査

一部の移植不可能なコードは、lint のデフォルトの動作によってフラグを付けられます。また、ほかにも少数の状況で、 -p または -Xc を指定して lint を起動すると、診断されることがあります。lint は ISO C 規格に一致しない言語構造を検査します。-p および -Xc のもとで発行されるメッセージに関しては、「4.6.2 lint ライブラリ」を参照してください。

次に例を示します。


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

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


short s;
long l;
s = l;

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


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

大部分のマシンでは、intchar とは異なり任意のバイト境界から開始することができないため、lint はフラグを立てます。-h を指定して lint を実行することによってこの診断を抑制することができます。この場合もまた、ほかのメッセージを抑制する可能性があります。汎用ポインタ void * を使用すればほかの影響を回避することができます。


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 x;
if (x < 0) ...

常に失敗します。一方、


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

これは次のように指定するのと同じことです。


if (x != 0) ...

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


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

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


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

int fun()
{
    int a, b, x, y;
    (a = x) && (b == y);
}

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

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


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

これは、ユーザーの意図とは異なる可能性が高いものです。-h を指定して lint を起動すると、診断のものは無効になります

4.6.2 lint ライブラリ

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

lint 標準 C ライブラリの llib-lc.ln は、デフォルトで lint コマンド行に追加されます。ライブラリ関数との互換性の検査は、-n オプションを指定して呼び出すことにより抑制することができます。そのほかの lint ライブラリは、-l に対して引数として指定することでアクセスされます。次に例を示します。


% lint -lx file1.c file2.c

この例では、lint ライブラリ llib-lx.ln との互換性について、file1.cfile2.c の関数と変数の使用方法を調べるよう lint に指示します。定義だけからなるライブラリファイルは、厳密に通常のソースファイルと .ln ファイルとして処理されます。ただしライブラリファイルで関数と変数が矛盾したまま使用されるか、またはライブラリファイルで定義されてもソースファイルでは使用されない関数と変数に対しては警告を出しません。

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


% lint -ox file1.c file2.c

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


% lint -y -ox file1.c file2.c

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

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


% lint -Ldir -lx file1.c file2.c

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

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


% cd <install-directory>/prod/src/lintlib; make

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

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

4.6.3 lint フィルタ

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

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