lint
プログラムを使用して,C プログラムにコーディング上の問題が含まれているかどうかを確認することができます。
lint
プログラムは C コンパイラよりも厳密にプログラムをチェックして,問題となりそうな点を指摘するメッセージを表示します。
メッセージのいくつかはソース・コードの修正が必要ですが,情報メッセージで修正を必要としないものもあります。
この章では,次の項目について説明します。
lint
コマンドの構文 (6.1 節)
プログラム・フロー・チェック (6.2 節)
データ型チェック (6.3 節)
変数と関数のチェック (6.4 節)
初期化前の変数使用のチェック (6.5 節)
移行チェック (6.6 節)
移植性チェック (6.7 節)
コーディング・エラーとコーディング・スタイルの相違のチェック (6.8 節)
大規模なプログラムのためのテーブル・サイズの増加 (6.9 節)
lint
ライブラリの作成 (6.10 節)
lint
エラー・メッセージ (6.11 節)
lint
メッセージ抑制のための警告クラス・オプションの使用 (6.12 節)
構文エラーのコンパイル時検出のための関数プロトタイプの生成 (6.13 節)
lint
のオプションの詳細については
lint
(1)6.1 lint コマンドの構文
lint
[ options ] [ file ... ]
lint
のオプションとして,cc
ドライバ・オプション
-std
,-std0
,-std1
を使用することができます。
これらのオプションは,使用する
lint
ライブラリの選択に影響を与えるとともに,ソースの解析に影響を与えます。
-std
あるいは
-std1
オプションを指定すると,lint
で ANSI 解析規則が有効になります。
-MA lint
オプションを使用すると,C プリプロセシングで
-std1
が使用され,-D
プリプロセッサ・オプションで
_ABSI_C_SOURCES
が定義されます。
次に示すのは,各オプションに対する
lint
の動作です。
lint オプション | プリプロセッサ・スイッチ | lint 解析 | lint ライブラリ |
-MA |
-std1
および
-D_ANSI_C_SOURCE |
ANSI | llib-lansi.ln |
-std |
-std |
ANSI | llib-lcstd.ln |
-std1 |
-std1 |
ANSI | llib-lcstd.ln |
-std0 |
-std0 |
EXTD [脚注 5] |
llib-lc.ln |
lint
が検査する C 言語のソース・ファイルの名前。
ファイル名には,次のいずれかの接尾語が必要です。
接尾語 | 説明 |
.c |
C ソース・ファイル |
.i |
C プリプロセッサ (cpp ) によって作成されるファイル |
.ln |
lint
ライブラリ・ファイル |
lint
ライブラリ・ファイルは,以前に
lint
プログラムを
-c
または
-o
オプションを指定して呼び出した結果です。
これは,cc
コマンドに入力として
.c
ファイルを指定した場合に,.o
ファイルが作成されるのと似ています。
lint
プログラムに入力として
lint
ライブラリが指定できる機能により,大規模なアプリケーションにおけるモジュール間のインタフェース・チェックが容易になります。
lint
ライブラリの構造を makefile に指定する規則を追加すると,そのようなアプリケーションをもっと効率よく作成できます。
lint
ライブラリの作成方法については,6.10 節を参照してください。
-lx
オプションを使用して,システムの省略時のライブラリ探索ディレクトリのいずれかにある
lint
ライブラリを入力として指定することもできます。
ライブラリ名は次の形式でなければなりません。
llib-llibname.ln
省略時の設定により,lint
プログラムは,拡張 C (K&R C)
lint
ライブラリ (llib-lc.ln
) を,コマンド行に指定されたファイルのリストに追加します。
-std
または
-std1
オプションが使用された場合は,標準 C
lint
ライブラリ (llib-lcstd.ln
) が代わりに追加されます。
ライブラリ | 説明 | 指定方法 |
crses |
curses ライブラリ呼び出し構文を検査する。 | -lcrses |
m |
算術ライブラリ呼び出し構文を検査する。 | -lm |
port |
他のシステムとの移植性を検査する。 | -p
(-lport
ではない) |
ansi |
ANSI C 規格の規則に準拠させる。 | -MA
(-lansi
ではない) |
コマンド行にオプションを指定しなければ,lint
プログラムは,指定の C ソース・ファイルを検査して,次のいずれかのコーディング上の問題が見つかった場合にはメッセージを書き込みます。
正常に開始および終了しないループがある。
正しく使用されていないデータ型がある。
正しく使用されていない関数がある。
正しく使用されていない変数がある。
プログラムを別のシステムに移植する際に,問題が発生する可能性があるコーディング技法が使用されている。
問題が発生する可能性がある,非標準的なコーディング技法やスタイルの違いがある。
また,lint
プログラムは,ソース・プログラムの文中に構文エラーがないかどうかを検査します。
構文検査は,lint
コマンドに指定したオプションに関係なく常に行われます。
lint
がエラーを報告しなければ,プログラムの構文に誤りがなく,正常にコンパイルされます。
ただし,検査をパスしても,プログラムが正確に動作する,またはプログラムの論理設計が正確であるということにはなりません。
ユーザ固有の
lint
ライブラリの作成方法については,6.10 節を参照してください。
6.2 プログラム・フロー検査
lint
プログラムは,デッド・コード,すなわち到達不可能なために実行されないプログラム部分がないかどうかを検査します。
プログラムの流れを変更する,goto
,break
,continue
,および
return
などの文の直後にあって,ラベルが付いていない文についてのメッセージを出力します。
lint
プログラムは,先頭から開始できないループについても検出して,メッセージを書き込みます。
このような型のループを含んだプログラムの中には,正しい結果を出すものもありますが,問題を引き起こす可能性があります。
lint
プログラムは,呼び出されても呼び出し元のプログラムに戻らない関数を認識しません。
たとえば,exit
を呼び出すと到達不可能なコードを生成しますが,lint
ではそのコードを検出できません。
yacc
と
lex
によって生成されたプログラムには,到達不可能な
break
文があります。
lint
プログラムは通常,これらの各
break
文に対するエラー・メッセージを出力します。
これらの
break
文に関連する余計なコードを取り除くには,プログラムをコンパイルするときに,cc
コマンドで
-O
オプションを使用します。
yacc
と
lex
の出力コードを検査するときには,lint
プログラムに
-b
オプションを使用すると,これらのメッセージは出力されません。
yacc
および
lex
についての情報は,『プログラミング・サポートツール・ガイド』を参照してください。
6.3 データ型検査
lint
プログラムは,C 言語のデータ型の検査規則をコンパイラが行うよりも厳密に適用します。
コンパイラが行う検査のほかに,lint
は,次のような点について,データ型エラーの可能性がないかどうかを検査します。
二項演算子と暗黙の代入
構造体と共用体
関数の定義および使用方法
列挙値
型検査制御
型キャスト
これらの問題の可能性についての詳細は,以降の各項で説明します。
6.3.1 二項演算子および暗黙の代入
C 言語では,文中に次のデータ型を混在させることができ,コンパイラは,その混在についてのエラーを示しません。
char
short
int
long
unsigned
float
double
C 言語では,上記のグループ内のデータ型を互いに自動的に変換するため,より柔軟にプログラミングできます。 ただし,この柔軟性は,C 言語自体によって保証されるものではないため,プログラマ自身が,データ型を混在させても確実に所定の結果が得られるようにする必要があります。
次の方法で使用する場合に,これらのデータ型を混在させることができます。
例では,alpha
が
char
型で,num
が
int
型です。
代入演算子の両辺のオペランドとして次のように使用する。
alpha = num; /* alpha を int に変換する。*/
条件式のオペランドとして次のように使用する。
value=(alpha < num) ? alpha : num; /* alpha を int に変換する。*/
関係演算子の両辺のオペランドとして次のように使用する。
if( alpha != num ) /* alpha を int に変換する。*/
return
文の引数の型は,次の例のように関数が返す値の型に変換される。
funct(x) /* integer を返す。*/ { return( alpha ); }
任意のデータ型の配列とその同じ型を指すポインタが混在する場合以外は,ポインタのデータ型は正確に一致しなければなりません。
6.3.2 構造体と共用体
lint
プログラムは,次のような条件の場合の構造体演算を検査します。
構造体ポインタ演算子 (->
) の左辺のオペランドは,構造体へのポインタでなければならない。
構造体メンバ演算子 (.
) の左辺のオペランドは,構造体でなければならない。
これらの演算子の右辺のオペランドは,同じ構造体のメンバでなければならない。
lint
プログラムは,共用体の参照についても同様の検査を行います。
6.3.3 関数定義と使用方法
lint
プログラムは,関数の引数とリターン値の照合に厳密な規則を適用します。
引数とリターン値は,型が一致している必要があります。
ただし,次のような例外があります。
float
型の引数と
double
型の引数を照合できる。
次の型の引数を互いに照合できる。
char
short
int
unsigned
ポインタを,それに対応する配列と照合できる。
lint
プログラムは,列挙データ型の変数が次の条件を満たしているかどうかを検査します。
列挙値変数または列挙型のメンバが,他の列挙値変数または他の型と混在していない。
列挙データ型の変数は,次の項目でのみ使用される。
C 言語のプログラムでは,型キャストによって,ある型のデータを別の型のデータのように扱うことができます。
lint
プログラムは,型キャストがないかどうかを検査し,もしあればメッセージを出力します。
lint
コマンド行に
-wp
および
-h
オプションを指定すると,キャストに関する警告メッセージの出力を制御します。
どちらのオプションも使用しなければ,lint
は移植性について問題が生じる可能性があるキャストに関して,警告メッセージを生成します。
移行検査モードでは,-Qc
でキャストの警告メッセージの出力が抑制されます(6.6 節を参照)。
6.4 変数および関数の検査
lint
プログラムは,プログラム内で宣言されていても使用されていない変数がないかどうかを検査します。
また,変数および関数の使用方法について次のエラーがないかどうかを検査します。
矛盾する値を返す関数
定義されているが使用されていない関数
関数呼び出しの引数で,使用されていない引数
値を返す関数または値を返さない関数
使用されない値を返す関数
関数が値を返さないのに,その関数の値を使用するプログラム
これらの問題の可能性について,以降の各項で説明します。
6.4.1 矛盾する値を返す関数
関数が,ある条件がそろっているときにしか値を返さない場合,プログラムの結果は予測することができません。
lint
プログラムは,関数がこのような動作をしないかどうかを検査します。
たとえば,次の 2 つの文が 1 つの関数定義にある場合には,その関数を呼び出すプログラムは,リターン値を受け取ったり,受け取らなかったりします。
return(expr);
.
.
.
return;
これらの文によって,lint
プログラムは,次のようなメッセージを出力し,問題の可能性を指摘します。
function name has return(e); and return
lint
プログラムはまた,関数コードの終端に到達したために発生するリターン (暗黙のリターン) がないかどうかについて,関数を調べます。
たとえば,次は関数の一部ですが,a
が偽と判断された場合は,checkout
は
fix_it
を呼び出し,リターン値なしで戻ります。
checkout (a) { if (a) return (3); fix_it (); }
これらの文に対して,lint
プログラムは,次のメッセージを出力します。
function checkout has return(e); and return
fix_it
が,exit
と同様に戻らない場合,lint
は,エラーがなくてもメッセージを出力します。
6.4.2 使用されていない関数値
lint
プログラムは,関数が値を返しても,呼び出しているプログラムがその値を使用していない場合がないかどうかを検査します。
値が使用されていない場合には,関数定義が無効である可能性があるため,調べて,変更するかまたは削除するかを決定します。
値が使用されることがある場合は,関数は,呼び出し側プログラムが検査をしていないという内容のエラー・コードを戻します。
6.4.3 関数についての検査の禁止
lint
が,関数についての問題を検査しないようにするには,lint
コマンドに次の表にあるオプションを 1 つまたは複数指定します。
-x |
extern
文で宣言されているが,使用されていない変数を検査しない。 |
-v |
レジスタ引数としても宣言されているものを除き,使用されていない関数の引数を検査しない。 |
-u |
使用されているのに定義されていない,または定義されているのに使用されていない関数および外部変数を検査しない。
大きなプログラムのファイルのサブセットで
lint
を実行する場合にこのオプションを使用すると,無駄なメッセージが削除される。
一緒に作動する一部の (全部ではない) ファイルで
lint
を使用すると,それらのファイルで定義されている関数および変数は,ほとんど使用されない。
また,その他のファイルで定義されている多くの関数および変数が使用される。 |
プログラムに指示文を記述しても,チェックを制御することができます。
使用されていない関数の引数について
lint
が警告メッセージを出力しないようにするには,プログラム中の当該関数定義の前に次の指示文を追加します。
/*ARGSUSED*/
関数の呼び出し時に,複数の引数について
lint
がメッセージを出力しないようにするには,関数定義の前に次の指示文を追加します。
/*VARARGS n*/
初めのいくつかの引数のみを検査し,その後の引数を検査しないようにするには,次のように
VARARGS
指示文の後に,検査すべき引数の数を 1 桁の数字 (n) で付加します。
/*VARARGS2*/
lint
は,この指示文を読み取った場合,先頭の引数を 2 つだけ検査します。
ファイル全体で使用されていない関数や関数の引数についてメッセージを抑制するには,次の指示文をファイルの先頭に記述します。
/*LINTLIBRARY*/
これは,-v
および
-x
オプションを使用する場合と同等です。
関数プロトタイプ宣言を関数定義のように記述することにより,標準プロトタイプ・チェック・ライブラリをヘッダ・ファイルから作成できるようにするには,次の指示文を使用します。
/*LINTSTDLIB
[
_filename
]
/*LINTSTDLIB*/
指示文は,/*NOTUSED*/
および
/*LINTLIBRARY*/
指示文の関数を暗黙に起動して,警告レベルを引き下げます。
ファイルが参照されると (filename),そのファイル内のプロトタイプのみが展開されます。
/*LINTSTDLIB_filename*
/
文は複数記述することができます。
/*LINTSTDLIB*/
指示文の使用方法については,6.10.1 項を参照してください。
ファイル内で検出され,使用されているが定義されていない外部シンボルおよび関数についての警告を抑制するには,次の指示文を使用します。
/*NOTDEFINED*/
到達不能なコードについてのメッセージを抑制するには,次の指示文を使用します。
/*NOTREACHED*/
プログラム内の適切な位置 (通常は
return
,break
,または
continue
文の直後) に記述すると,/*NOTREACHED*/
指示文は,到達不能なコードについてのメッセージ出力を停止します。
lint
は,exit
関数およびリターンしないかも知れない他の関数を認識しません。
ファイル内で検出されるが,使用されていない外部シンボル,関数,および関数パラメータについての警告メッセージを抑制するには,次の指示文を使用します。
/*NOTUSED*/
/*NOTUSED*/
指示文は
/*LINTLIBRARY*/
指示文と同等ですが,/*NOTUSED*/
は外部シンボルに対しても適用されます。
lint
プログラムは,ローカル変数 (auto
と
register
の記憶クラス) が,値を割り当てられていないのに使用されていないかどうかを検査します。
auto
(自動) 記憶クラスまたは
register
記憶クラスで変数を使用するには,変数のアドレスも取得することが必要です。
これは,プログラムが変数のアドレスを認識すれば,いつでもそのアドレスによって変数を使用できるためです。
したがって,プログラムが,変数に値を割り当てていないにもかかわらず変数のアドレスを見つけようとした場合,lint
はエラーを報告します。
lint
はファイル内での変数の物理的な順番と使用されているかどうかを検査するだけであるため,適切に初期化された変数についてのメッセージを実行順に出力することがあります。
lint
プログラムは,次の項目を認識してメッセージを出力します。
初期化された自動変数
最初に変数を設定する式に使用される変数
設定されていても使用されていない変数
注意
Tru64 UNIX オペレーティング・システムは,
static
変数とextern
変数をゼロに初期化します。 したがって,lint
はプログラムの開始時にこれらの変数が 0 に設定されていると見なし,その変数にすでに値が割り当てられているかどうかについては,変数の使用時には確認しません。 このような初期化を行っていないシステムのプログラムを開発する場合は,プログラムがstatic
変数とextern
変数を初期値に設定していることを確認してください。
lint
を使用して,32 ビット・オペレーティング・システムから Tru64 UNIX オペレーティング・システムに移行する場合に,問題が発生する可能性のあるすべての一般的なプログラミング技法を検査します。
-Q
オプションは,64 ビット・システムに移行する ULTRIX および DEC OSF/1 バージョン 1.0 プログラムのチェックをサポートします。
-Q
オプションを指定すると,その他のプログラム上の問題の検査ができなくなります。
このため,移行検査の目的だけで使用してください。
サブオプションは,特定のカテゴリの検査を抑止するために使用できます。
たとえば,-Qa
と入力すると,ポインタの位置合わせに関する問題を検査しません。
-Q
オプションには複数のサブオプションを指定することができます。
たとえば
-QacP
は,ポインタ位置合わせの問題,問題のある型キャスト,および関数プロトタイプの検査をそれぞれ抑止します。
移行検査についての詳細は,
lint
(1)6.7 移植性検査
lint
を使用すると,異なる C 言語コンパイラや他のシステムを使用している C プログラムのコンパイルおよび実行が確実にできるようになります。
以降の各項で,他のシステム上でプログラムをコンパイルする前に確認すべき点を示します。 ただし,これらの点だけを確認すれば,どのシステムでもプログラムが実行可能であるというわけではありません。
注意
llib-port.ln
ライブラリは,-lport
オプションではなく,-p
オプションを使用すると,取り込むことができます。
システムの中には,C 言語プログラムで使用する文字を,--128 以上 127 以下の符号付きの数として定義しているものもあります。
その他のシステムでは文字を正の値で定義しています。
lint
プログラムは,他のシステムに移植できない可能性のある文字の比較または文字の代入がないかどうかを検査します。
たとえば,次のコードの一部は,あるシステムでは動作しますが,文字が常に正の値を取るシステムでは動作しません。
char c;
.
.
.
if( ( c = getchar() ) <0 )...
この文により,lint
プログラムは,次のようなメッセージを出力します。
nonportable character comparison
文字を正の値で定義しているシステムでプログラムを動作させるには,getchar
が整数値を返すため,c
を整数として宣言します。
6.7.2 ビット・フィールド
プログラムを別のシステムに移植する際,ビット・フィールドに問題がある可能性があります。
新しいシステムではビット・フィールドも符号付き数である可能性もあります。
したがって,ビット・フィールドに定数値を代入する場合は,フィールドが小さすぎて値を保持できない可能性があります。
すべてのシステムで定数値の代入ができるようにするには,定数値を設定する前に,ビット・フィールドを
unsigned
型として宣言します。
6.7.3 外部名サイズ
あるタイプのシステムから別のタイプのシステムに変更する場合は,プロセスのロード時に得られる外部名についての情報に,次のような相違があることに注意してください。
外部名に許される文字数が異なる。
コンパイラ・コマンドが呼び出すプログラム,およびプログラムが呼び出す関数が,識別子の有効文字数をさらに制限する場合がある。
また,コンパイラはすべての名前の前に下線を追加して,大文字と小文字を区別します。
大文字と小文字を区別しないシステムと,区別され混在が許されないシステムがある。
あるシステムから別のシステムに移植する場合は,プログラムのロード時の問題を避けるため,常に次の手順を行ってください。
各システムの条件を調べる。
-p
オプションを付けて
lint
を実行する。
-p
オプションを付けると,lint
は,すべての外部シンボルを小文字に変更し,入力ファイルの検査時には 6 文字以内に制限します。
出力されたメッセージには,変更が必要な用語が示されます。
6.7.4 複雑な式の使用と副作用
複雑な式を使用する場合には,次の点に注意してください。
複雑な式が評価される順序は,各 C コンパイラによって異なる。
他の関数の引数となっている関数の呼び出しは,通常の引数としては扱われない。
代入,インクリメント,およびデクリメントなどの演算子を異なるシステムで使用すると,問題が起こる可能性がある。
次に,これらの相違が原因で起こる 3 種類の問題の例を示します。
前述のいずれかの演算子の副作用によって任意の変数が変更され,その変数が同じ式の別の場所で使用されている場合,結果は未定義になる。
次の
printf
文では,変数
years
の評価は混乱する。
これは,years
を関数呼び出しの前に増分するマシンもあれば,関数呼び出しの後で増分するマシンもあるためです。
printf( "%d %d\n", ++years, amort( interest, years ) );
lint
プログラムは,次の文に示されるような,評価の順序に影響されるおそれのある単純なスカラ変数を検査する。
a[i]=b[i++];
この文により,lint
プログラムは次のメッセージを出力します。
warning: i evaluation order undefined
6.8 コーディング・エラーおよびコーディングのスタイルの相違のチェック
lint
は,発生し得るコーディング・エラーを検出したり,lint
が予期しているコーディング・スタイルとの相違を検出したりします。
コーディング・スタイルは主として個人の趣味の問題ですが,相違する点は,正しくかつ必要なものであることを確認してください。
以降の各項で,lint
が検出するコーディング・エラーおよびコーディング・スタイルについての問題を示します。
6.8.1 long 型変数の int 型変数への代入
long
型の変数を
int
型の変数に代入すると,プログラムは正しく動作しません。
long
型変数は,int
型変数のスペースに適合するように切り捨てられるため,データが失われる可能性があります。
typedef
を使用するプログラムを変換して異なるシステム上で実行すると,この種のエラーが頻繁に発生します。
long
変数の
int
変数への代入を検出した場合,lint
がメッセージを書き込まないようにするには,-a
オプションを使用します。
6.8.2 演算子の優先度
lint
プログラムは,演算子の優先度に関するエラーを検出します。
複雑なシーケンス内では順番を表すカッコがなければ,このエラーの検出は困難です。
たとえば,次の文では優先度がはっきりしていません。
if(x&077==0). . . /* if(x & (077 == 0))と評価される。*/ /* 本来はif((x & 077) == 0)である。*/ x<<2+40 /* x <<(2+40) と評価される。*/ /* 本来は (x<<2) + 40 である。*/ /* x を左へ 42 文字だけシフトする。*/
カッコを使用して演算がより明解になるようにしてください。
カッコを使用しない場合には,lint
はメッセージを出力します。
6.8.3 宣言の矛盾
lint
プログラムは,内部ブロックで宣言される変数が,外部ブロックでの宣言と矛盾するような場合に,メッセージを出力します。
この変数を実行することはできますが,プログラムに問題が起こる可能性があります。
lint
プログラムに
-h
オプションを付けると,lint
は,宣言の矛盾がないかどうかを検査しません。
6.9 テーブル・サイズの増加
lint
コマンドの
-N
オプションおよび関連のサブオプションは,さまざまな内部テーブルのサイズが,省略時の値ではプログラムを動作させるのに不十分な場合,実行時に増加させます。
内部テーブルには次のようなものがあります。
シンボル・テーブル
ディメンション・テーブル
ローカルの型テーブル
解析ツリー
これらのテーブルは,lint
プログラムによって動的に割り当てられます。
大きなソース・ファイルについて
-N
オプションを使用すると,性能を向上させることができます。
6.10 lint ライブラリの作成
システム・ライブラリ・ルーチン以外のライブラリ・ルーチンを作成するプログラム開発プロジェクトでは,さらに
lint
ライブラリを作成して,プログラムの構文を検査することができます。
lint
プログラムは,lint
ライブラリを使用して,C 言語の標準関数だけでなく,新しい関数を検査することができます。
新しい
lint
ライブラリを作成するには,次の手順を実行してください。
新しい関数群を定義する 1 つの入力ファイルを作成する。
1.
の入力ファイルを処理して
lint
ライブラリ・ファイルを作成する。
2.
で作成した
lint
ライブラリを使用して,lint
を実行する。
以降の各項で,これらの手順についての詳細を説明します。
6.10.1 入力ファイルの作成
次の例は,lint
に検査させる関数を 3 つ定義した入力ファイルです。
/*LINTLIBRARY*/ #include <dms.h> int dmsadd( rmsdes, recbuf, reclen ) int rmsdes; char *recbuf; unsigned reclen; { return 0; } int dmsclos( rmsdes) int rmsdes; { return 0; } int dmscrea( path, mode, recfm, reclen ) char *path; int mode; int recfm; unsigned reclen; { return 0; }
入力ファイルとは,エディタで作成するテキスト・ファイルのことで,次のものから構成されます。
/*LINTLIBRARY*/
の指示文
その後に続く情報を
lint
定義のライブラリとして作成するように
cpp
プログラムに指示します。
次の項目を定義する一連の関数定義
関数の型 (上記の例では
int
)
関数の名前
関数が予期するパラメータ
パラメータの型
関数が返す値
もう 1 つの方法として,関数プロトタイプから
lint
ライブラリ・ファイルを作成することができます。
たとえば,dms.h
ファイルに次のプロトタイプが含まれているとします。
int dmsadd(int, char*, unsigned); int dmsclose(int); int dmscrea(char*, int, int, unsigned);
この場合,入力ファイルには次の記述が含まれます。
/*LINTSTDLIB*/ #include <dms.h>
ヘッダ・ファイルに別のヘッダ・ファイルが含まれている場合は,LINTSTDLIB
コマンドは特定のファイルに制限されます。
/*LINTSTDLIB_dms.h*/
この場合は,dms.h
で宣言されたプロトタイプのみが展開されます。
LINTSTDLIB
コマンドは複数記述することができます。
いずれの場合にも,入力ファイルの名前には,接頭語
llib-l
がなければなりません。
たとえば,この項で作成されるサンプルの入力ファイルの名前は,llib-ldms
となります。
ファイルに名前を付ける場合は,/usr/ccs/lib
ディレクトリにある既存のファイルと同じ名前でないことを確認してください。
6.10.2 lint ライブラリ・ファイルの作成
次のコマンドは,前項で説明した入力ファイルから
lint
ライブラリ・ファイルを作成します。
% lint [options] -c llib_ldms.c
このコマンドは,入力ファイルとして
llib-ldms.c
を使用して,lint
ライブラリ・ファイル
llib-ldms.ln
を作成するように
lint
に指示しています。
その後
llib-ldms.ln
をシステム
lint
ライブラリ (つまり,lint
コマンドの
-l
x
オプションで指定するライブラリ) として使用するには,それを
/usr/ccs/lib
に移動します。
ANSI 前処理規則を使用してライブラリを構築するには,-std
または
-std1
オプションを使用します。
6.10.3 新しいライブラリによるプログラムの検査
新しいライブラリを使用してプログラムを検査するには,次の形式で
lint
コマンドを使用します。
lint -lpgm filename.c
pgm
変数にはライブラリの識別子を,filename.c
変数には,検査する C 言語のソース・コードの入っているファイル名を指定します。
他のオプションが指定されていない場合,lint
プログラムは,指定された特定の
lint
ライブラリだけでなく,標準の
lint
ライブラリとも照合して,C 言語ソース・コードを検査します。
6.11 lint エラー・メッセージ
lint
のエラー・メッセージのほとんどはわかりやすいものですが,説明を加えなければ誤解が生じやすいメッセージもあります。
通常,メッセージの意味を理解すると,エラーの修正は簡単です。
次に,意味のあいまいな
lint
メッセージを示します。
constant argument to NOT
定数が NOT 演算子 (!) と一緒に使用されています。
これは一般的に行われるコーディングであり,必ずしも問題を示しているわけではありません。 次のようなコーディングをすると,このメッセージが出力されることがあります。
% cat x.c #include <stdio.h> #define SUCCESS 0 main() { int value = !SUCCESS; printf("value = %d\n", value); return 0; } % lint -u x.c "x.c", line 7: warning: constant argument to NOT % ./x value = 1 %
lint
はメッセージを出力しますが,プログラムは期待どおりに実行されます。
対応策:
-wC
オプションを使用して,lint
の警告メッセージを出力しないようにします。
constant in conditional context
条件を指定すべきところに定数が使用されています。
この問題は,マクロの使用方法によって,ソース・コードでよく起こります。 たとえば,次のような場合です。
typedef struct _dummy_q { int lock; struct _dummy_q *head, *tail; } DUMMY_Q; #define QWAIT 1 #define QNOWAIT 0 #define DEQUEUE(q, elt, wait) [1] \ for (;;) { simple_lock(&(q)->lock); if (queue_empty(&(q)->head)) if (wait) { [1] \ assert(q); simple_unlock(&(q)->lock); continue; } else *(elt) = 0; else dequeue_head(&(q)->head); simple_unlock(&(q)->lock); break; } int doit(DUMMY_Q *q, int *elt) { DEQUEUE(q, elt, QNOWAIT); }
QWAIT
または
QNOWAIT
オプションは 3 番目の引数 (wait
) として渡され,その後
if
文で使用されます。
コードは正しいのですが,lint
は警告メッセージを出力します。
これは,通常このように使用される定数は不必要であり,無駄な命令を生成するためです。
[例に戻る]
-wC
オプションを使用して,lint
の警告メッセージを出力しないようにします。
conversion from long may lose accuracy
符号付き
long
が小さい要素 (int
など) にコピーされています。
このメッセージは必ずしも誤解を招くものではありませんが,よく起こり,次の例に示すように,コーディングに問題がある場合もあれば,問題がない場合もあります。
long BuffLim = 512; [1] void foo (buffer, size) char *buffer; int size; { register int count; register int limit = size < (int)BufLimit ? size : (int)BufLim; [1]
適切な
(int)
キャストが使用されていますが,lint
プログラムは変換エラーを報告します。
[例に戻る]
lint
がメッセージを報告するコード・セクションを調べるか,または
-wC
オプションを使用して,lint
の警告メッセージを出力しないようにします。
declaration is missing declarator
プログラムの宣言節にセミコロン (;) だけの行があります。
このようなコードを書かなくても,マクロの後ろにセミコロンを記述した場合などに,このようなコードが生成されることがあります。 条件化により,マクロが空として定義された場合,このメッセージが出力されることがあります。
対応策: 後ろのセミコロンを削除してください。
degenerate unsigned comparison
結果がゼロより小さくなると思われる場合に,符号なし比較が符号付きの値に対して実行されました。
次のようなプログラムでこのメッセージが出力されます。
% cat x.c #include <stdio.h> unsigned long offset = -1; main() { if (offset < 0) { [1] puts ("code is Ok..."); return 0; } else { puts ("unsigned comparison failed..."); return 1; } } % cc -g -o x x.c % lint x.c "x.c" line 7: warning: degenerate unsigned comparison % ./x unsigned comparison failed... %
このような符号なし比較は,符号なし変数に負の値が入っている場合には失敗します。 符号付き比較を意図していたかどうかによって,結果のコードは正しいこともあります。 [例に戻る]
if
比較の
offset
の前に
(long)
キャストを追加する。
offset
の宣言を
unsigned long
から
long
に変更する。
場合によっては,符号付きの値を符号なしにキャストする必要があります。
function prototype not in scope
このエラーは厳密には関数プロトタイプに関連していません。 実際,このエラーは前もって宣言や定義を行っていない関数を呼び出した場合に起こります。
対応策: 関数プロトタイプ宣言を追加してください。
null effect
lint
プログラムが何も行わないキャストまたは文を検出しました。
次のコードは,lint
がこのメッセージを出力するさまざまなコーディング例を示しています。
scsi_slot = device->ctlr_hd->slot,unit_str; [1] #define MCLUNREF(p) \ (MCLMAPPED(p) && --mclrefcnt[mtocl(p)] == 0) (void) MCLUNREF(m); [2]
対応策: 不必要なキャストや文を削除したり,マクロを修正してください。
possible pointer alignment problem
位置合わせの問題が生じるような方法でポインタが使用されています。
次のコードは,lint
によりこのメッセージが生成されるコード例を示しています。
read(p, args, retval) struct proc *p; void *args; long *retval; { register struct args { long fdes; char *cbuf; unsigned long count; } *uap = (struct args *) args; [1] struct uio auio; struct iovec aiov;
*uap = (struct args *) args
という文が,このエラーを引き起こします。
この構文は有効であり,カーネル・ソース内で使用されるため,このメッセージはフィルタされます。
[例に戻る]
precision lost in field assignment
ビット・フィールドがある値を保持するには小さすぎる場合に,そのフィールドにその定数を代入しようとしました。
次のコードはこの問題を示しています。
% cat x.c struct bitfield { unsigned int block_len : 4; } bt; void test() { bt.block_len = 0xff; } % lint -u x.c "x.c", line 8: warning: precision lost in field assignment % cc -c -o x x.c %
このコードはエラーを生じることなくコンパイルされます。 ただし,ビット・フィールドがその定数を保持するには小さすぎるため,意図した結果にならず,実行時エラーが生じる場合もあります。
対応策: ビット・フィールドのサイズを変更するか,または異なる定数値を代入してください。
unsigned comparison with 0
結果がゼロに等しいか大きいと予想される場合に,ゼロに対して符号なしの比較が実行されました。
次のプログラムは,このような状況を示しています。
% cat z.c #include <stdio.h> unsigned offset = -1; main() { if (offset > 0) { [1] puts("unsigned comparison with 0 Failed"); return 1; } else { puts("unsigned comparison with 0 is Ok"); return 0; } } % cc -o z z.c % lint z.c "z.c", line 7: warning: unsigned comparison with 0? % ./z unsigned comparison with 0 Failed %
このような符号なし比較は,符号なし変数に負の値が入っている場合に失敗します。 符号付き比較を意図していたかどうかによって,結果のコードは正しくない場合があります。 [例に戻る]
if
比較の
offset
の前に,(int)
キャストを追加する。
offset
の宣言を
unsigned
から
int
へ変更する。
6.12 警告クラス・オプションを使用した lint メッセージの抑制
lint
プログラムにいくつかの
lint
警告クラスを追加することによって,条件処理で使用される定数,移植性,およびプロトタイプの検査に関連したメッセージの出力を抑制できるようになりました。
lint
コマンドで警告クラス・オプションを使用すると,どの警告クラスのメッセージでも抑制することができます。
警告クラス・オプションのフォーマットは次のとおりです。
-wclass
[ class... ]
省略時の設定ではすべての警告クラスがアクティブですが,class 引数として適切なオプションを指定すると,個々のクラスを非アクティブにすることができます。 表 6-1 で個々のオプションについて説明します。
注意
lint
メッセージには,複数の警告クラスに依存するものがいくつかあります。 したがって,これらのメッセージを抑制するには,複数の警告クラスを指定する必要があります。 表 6-1 の脚注は,複数の警告クラスを指定して,どのメッセージが抑制できるかだけを示しています。
たとえば,条件式の定数に関連する
lint
メッセージは,(6.11 節で説明しているように) 必ずしもコーディング上の問題を示していないので,-wC
オプションを使用してメッセージを抑制するとします。
-wC
オプションは,次のメッセージの出力を抑制します。
constant argument to NOT
constant in conditional context
移植性の検査に関するメッセージの多くは,非 ANSI コンパイラおよび Tru64 UNIX 用の C コンパイラに存在しない制限に関連するため,-wp
オプションを使用して,メッセージを抑制することができます。
-wp
オプションは,次のメッセージの出力を抑制します。
ambiguous assignment for non-ansi compilers
illegal cast in a constant expression
long in case or switch statement may be truncated in
non-ansi compilers
nonportable character comparison
possible pointer alignment problem, op %s
precision lost in assignment to (sign-extended?) field
precision lost in field assignment
too many characters in character constant
関数プロトタイプの使用は (6.13 節で説明しているように) 好ましいコーディング方法ですが,多くのプログラムでは使用されていません。
-wP
オプションを使用すると,プロトタイプの検査を禁止することができます。
-wP
オプションは,次のメッセージの出力を抑制します。
function prototype not in scope
mismatched type in function argument
mix of old and new style function declaration
old style argument declaration
use of old-style function definition in presence of
prototype
警告クラス | クラスの説明 |
a |
非 ANSI 機能。 次のメッセージの出力を抑制する。
|
c |
符号なし値の比較。 次のメッセージの出力を抑制する。
|
d |
宣言の一貫性。 次のメッセージの出力を抑制する。
|
h |
ヒューリスティックな障害。 次のメッセージの出力を抑制する。
|
k |
K & R 型のコードを期待する。 次のメッセージの出力を抑制する。
|
l |
非 long 型変数に long 型の値を代入した。 次のメッセージの出力を抑制する。
|
n |
空作用コード。 次のメッセージの出力を抑制する。
|
o |
未知の評価順序。 次のメッセージの出力を抑制する。
|
p |
移植性に関連するさまざまな事柄。 次のメッセージの出力を抑制する。
|
r |
Return 文の一貫性。 次のメッセージの出力を抑制する。
|
S |
記憶容量の検査。 次のメッセージの出力を抑制する。
|
u |
変数および関数の適切な使用。 次のメッセージの出力を抑制する。
|
A |
すべての警告クラスをアクティブにする。
|
C |
条件処理で使用されている定数。 次のメッセージの出力を抑制する。
|
D |
外部宣言が使用されていない。 次のメッセージの出力を抑制する。
|
O |
使用されていない機能。 次のメッセージの出力を抑制する。
|
P |
プロトタイプの検査。 次のメッセージの出力を抑制する。
|
R |
実行されないコードの検出。 次のメッセージの出力を抑制する。
|
6.13 コンパイル時に検出される構文エラーのための関数プロトタイプの生成
lint
プログラムが報告するさまざまなエラーの修正に加えて,外部関数および静的関数の両方に対して関数プロトタイプを追加することをお勧めします。
この宣言は,コンパイラが検査する必要のある引数およびリターン値の情報を提供します。
cc
コンパイラには,自動的にプロトタイプ宣言を生成するオプションがあります。
コンパイル時に
-proto[is]
オプションを指定すると,関数プロトタイプを含む出力ファイル (入力ファイルと同じファイル名でファイル・タイプが
.H
) を作成することができます。
i
オプションを指定するとプロトタイプに識別子を含み,s
オプションを指定すると静的関数に対してもプロトタイプを生成します。
.H
ファイルから関数プロトタイプをコピーしてソース内の適切な場所に挿入し,ファイルを取り込みます。