CやC++をはじめとする言語の仕様は、曖昧に書かれていることが多いものです。 lint と呼ばれるツールを使用すると、コンパイラが実行時のバグに変える前に、コード内の危険で移植不可能な構造を見つけることができます。
プログラムを書いたことのある人なら誰でもコードをデバッグしなければなりません。 多くの場合、何時間もコードを見ているうちに、初期化されていない変数を読み込んだり、配列の終わりを超えてインデックスを作成するなど、何か愚かなことをしたことにようやく気づきます。
このようなときに必要なのは、コードを隅々までチェックする、無限の忍耐力と分析力を持った専門家です。 この専門家は、どんなコンパイラよりも徹底していなければならず、私たちのコードで潜在的に間違っていることをすべて、完全に冷静な方法で報告しなければなりません。 この理想に最も近いのが「lint」というプログラミングツールです。 もしあなたが lint が何であるか知らない、または使用していないのであれば、これを読むことをお勧めします。
Lintは、C/C++のソースファイルを解析するという点で、コンパイラに似たツールです。 Lintは、C/C++のソースファイルを解析し、構文的に正しいかどうかをチェックします。 foo.c というファイルを lint するには、通常、コマンド ラインで次のように入力します。
標準的な機能
コンパイラが主にコード生成に関わるのに対し、lint はコードに無数の可能性のある欠陥がないかどうかをチェックすることに専念します。 ここで重要なのは「可能性」です。
Lint はコンパイラに依存しないように設計されており、実際、使用される特定のコンパイラに応じて異なる動作をする可能性のあるコードの部分に注意を向けるという仕事を頻繁に行っています。
Lint がチェックする問題の具体的なリストは、ツールの実装やバージョンによって異なりますが、ほとんどのフレーバーの lint は、少なくとも以下をチェックします。
- 初期化されていない変数の使用の可能性
- 配列の境界を越えたインデックスの可能性
- 脱ヌル ポインタの参照解除
- 疑わしい代入 (if (a = b) など)
- 変数の型の不一致 (foo があるファイルでは double として宣言され、別のファイルでは long として使用されているなど)
- 潜在的に危険なデータ型の組み合わせ
- 未使用の変数
- 到達できないコード
- 複数回または不必要に含まれるヘッダー ファイル
- 非移植性のない構造
i
Lintは非常に多くのことをチェックします。 実際、Lint は非常に多くのことをチェックしますので、入力されたソース ファイルのコード行数と同じ数のエラーや警告を出力するのが普通です。 これは、多くの潜在的なユーザーにとっては、「このツールはとてもうるさいので、馬鹿げている」という態度をとることになります。 しかし、一つ一つの警告を確認して修正していくことは、とてもやりがいのある作業です。 例として、次のような一見何の問題もないコードを考えてみましょう。 もしあなたが「100」と答えたなら、それは間違いです。 これは完全に正しいプログラムであり、ほとんどのコンパイラで警告なしにコンパイルできます。 しかし、Lintは何かを訴えてきます。 もし、検査しても問題がわからない場合は、www.embedded.com/code.htm からコードをダウンロードして、お好みのデバッガで実行することをお勧めします。 注意していただきたいのは、大きなヒントですが、このプログラムを単にエディタに入力しないでください。
Lint を除去する
上記の少し作為的な例にもかかわらず、Lint によって生成されたすべての警告に対処することで、実世界でどのような利益が期待できるでしょうか。
- コードのテストを開始する前に、Lint は 2 つまたは 3 つの明白なバグを発見しました。
- 実行するたびに、C 言語について何かを学びました。
- 安全に削除できる未使用の変数、マクロ、およびヘッダー ファイルのインクルードについて Lint が教えてくれたので、最終的なコードはよりクリーンになりました。
- 潜在的な移植性の問題をよりよく知ることができました。
以上のことから、コードの品質に真剣に取り組んでいる組織が、すべてのコードを警告なしにコンパイルすること (これは比較的簡単に達成できることです) だけでなく、「lint free」、つまり、lint で警告を生成しないことを要求することが多いことを知っても、おそらく驚かないでしょう。 これは、達成するのがはるかに難しい基準です。
図1: 開発プロセスにおけるlintの位置づけ
開発プロセスにおけるlintの位置づけを見てみましょう。 私の一般的な設計フローを図1に示します。 コンパイルしたコードができたら、それをlintします。 lintが問題なく通れば、コードレビューで恥ずかしい思いをすることはまずありません。 デバッグの段階では、コードに変更が加えられるのが普通です。 しかし、コードがデバッグされた後、リリーステストに渡される前に、私は通常、コードを再びlintします。 なぜでしょう? コードがデバッグされているときに発生する、ずさんなコーディング構造の多さにはいつも驚かされます。
Lint のソース
Lint はほとんどの Unix システムで標準的なツールです。 PC の世界では、多くの場合、購入するか、フリーまたはシェアウェアのバージョンを見つけなければなりません。 もし、Lint を購入するなら、それはおそらくあなたの組み込みのキャリアの中で最高のお金になるでしょうから、安心してください。
ちなみに、組み込み開発で一般的な厄介な小さなコンパイラ拡張を、lint がどの程度処理できるのか気になるかもしれません。 これは、商用プログラムが標準製品よりも優れている分野です。 特に、いくつかのバージョンのlintでは、lintのルールをかなりカスタマイズすることができ、これらの拡張機能をすべて正しく処理することができます。 いくつかのケースでは、コンパイラの定義がlintのベンダーによって提供されています。
もしあなたが lint にアクセスできず、GNU ツール (Unix または PC) を使用している場合、gcc の -Wall フラグを使用するだけで、同じ機能の約 80% を実現することができます。 何はともあれ、あなたの上司はあなたのコードの成熟度に感心するでしょう。 lintを使っていない経験豊富なハッカーの皆さん、気をつけてください。 使っている新しい人たちが、あなたを見つけてくれるかもしれません。
Nigel Jonesはメリーランド州でコンサルタントをしています。 海に潜っていないときは、さまざまな組み込みプロジェクトに没頭しています。
Nigel Jonesはメリーランド州のコンサルタントです。