こんにちは､ そしてお帰りなさい｡
この講義では､ 一般的なコンパイラと警告についてだけ説明したいと思います｡
よくあるCの問題点をお話しました｡
しかし､ コンパイラがそれを伝えようとしているのに､ 自分のプログラムにそういうエラーがあることに気づかないこともある｡
コンパイラのエラーや警告は､ 新米プログラマーにとっては実に不可解なものです｡
セミコロンが足りないと言っているのかもしれませんが､ unreachable end of statementと表示されます｡
そして､ 初めての人には､ それが何を意味するのかわからないかもしれません｡
ですから､ たくさんのコードを書いて､ 時間をかけてコンパイラの警告のいくつかを読み解くには､
かなりの練習が必要なのです｡
でも､ その前にお知らせしておきたいことがあります｡
そこで､ 前回の講義で見た一般的な問題のいくつかについて､
実際にコンパイラの警告やエラー､ そしてその内容を説明します｡
コンパイラが何を伝えているかを理解するように伝えることは､ とてもとても重要なことなのです｡
コンパイラがエラーを教えてくれても､ そのエラーを理解できなければ､
そのコードを修正するのに時間がかかってしまう｡
しかし､ もしエラーが表示され､ その内容を正確に理解できれば､
すぐに修正することができます｡
そういえば､ プログラミングを始めたばかりの頃､ 研究室にいるとセミコロンが抜けていることがよくありました｡
コンパイラはセミコロンが足りないことを教えてくれるのですが､
私にはそれがわからず､ unreachable end of statementと表示されるだけで､ 「これはどういう意味だ､
文とは何だ？ 私なら､ とても迷いますね｡
そこで､ コンパイラが実際に何を伝えようとしているのか､ そのヒントを提供したいと思ったわけです｡
だから､ コンパイラが何を訴えているのか､ 非常にわかりにくい｡
これらのメッセージを読み解くことは､
時に非常に困難なことです｡
ですから､ これらのコンパイラーエラーを理解することが､ 修正するために必要なのです｡ とても基本的なことです｡
そして､ コンパイラが仕事の半分をやってくれているのです｡
シンタックスをチェックして､ 何が間違っているのかを正確に教えてくれるから､
それをうまく利用するといい｡
しかし､ 特に初心者が用語を理解できない場合､ 何を言っているのか正確に理解するのは難しいことがあります｡
コンパイラは､ プログラマがコードに書いていない､ コードをどのように翻訳するかという判断をします｡
これは､ プログラムやコンパイラにとって便利で､ より簡潔に書くことができるようになります｡
そして､ この機能を活用するのは､ 熟練したプログラマーだけです｡
つまり､ コンパイルするときは必ずダッシュウォールオプションを使えということです｡
これで､ すべてのスイッチが入る｡
そのため､ より高度な機能として､ 実際にいくつかの項目を削除し､
翻訳をもう少し効率的に行うこともできます｡
しかし､ それを追加すると､
プログラムのコンパイルが異なってしまうのです｡
そしてその結果､ あなたの知らないところでコードに警告が発生しているかもしれません｡
なぜこのようなことを言うかというと､ 常にあるオプション､ つまりダッシュウォールオプションでコンパイルしたいからです｡
実は､ コードブロックはデフォルトでオンになっているんです｡
そして､ これはコンパイラがあなたの知らないところでやっているすべてのケースを通知してくれます｡
また､ すべての警告をオンにして､ 多くの情報を与えてくれる､
非常に便利なコンパイラ・オプションです｡
このオプションをオンにすると､ コンパイラが教えてくれることをよりよく理解できるようになります｡
つまり､ コンパイラは2種類の問題を表示することになる｡
1つはエラーです｡
これによって､ 実際にプログラムを作成することができなくなります｡
シンタックスエラーがあり､ プログラムをコンパイルすることができません｡
実行可能な作品が再現されていない､
と｡ 通常､ コンパイラからのエラーが表示されると､ 常にその最初のエラーに注目したくなるものです｡
他のエラーの中には､ その最初のエラーの結果である可能性もあるので､
それが最も信頼できるエラーです｡
だから､ 常にその最初のエラーに注目する｡ まず先頭のエラーを修正し､ 再度コンパイルして他のエラーが消えるかどうか確認してください｡
警告 警告は､ 特殊な状況や何らかの異常が検出された場合に､
コンパイラが表示するメッセージです｡
致命的でないエラーです｡ そこで､ 実行ファイルが作成されることになります｡
でも､ やっぱり直した方がいいものです｡
警告には理由があるのです｡ やり方が間違っているか､ 将来的に問題が発生する可能性があります｡
だから､ 警告は必ず全部直したいんですね｡
また､ dash wallオプションでコンパイルすることで､
すべての警告がなくなるまで､ プログラムが正しいとはみなしません｡
だから､ コンパイルに失敗することはない｡ このため､ コンパイラによって起こっていることをすべて見るだけでなく､
このオプションを使うように言っているのです｡
よくあるコンパイラのメッセージは､
先ほどのcの問題に直接関係するものです｡
変数が宣言されていない場合､ この関数を使用すると､ 最初にこのメッセージ variable undeclared
が表示されます｡
これは最も一般的なものの一つで､ 通常､ 検出が容易です｡
そして､ このメッセージの前にシンボルマークも表示されます｡
基本的には､ この変数を使おうとしているが､
実際には宣言していない､ と表示されます｡
変数を宣言するときに､ データ型を指定することは知っています｡
存在しない変数にデータを署名することはできないのです｡
暗黙のうちに関数を宣言している場合､ 関数の宣言に関わる警告です｡
関数を呼び出そうとしたとき､ その関数に実装が関連付けられていない場合です｡
ヘッダーを入れてないのか､
宣言してないのか｡ だから､ どこにあるのかわからないし､
関数がどのように宣言されているのかも､ 引数も､ 戻り値もわからないのです｡
機能そのものに関する情報がない？
これを解決するには､ 常に関数のプロトタイプを先頭で宣言することです｡
もう一つの警告は､ warning control reaches end of non-void functionと表示されます｡
これは､ 関数が結果を返すと定義されていて､ それが非voidであるにもかかわらず､ 関数内にreturn文が含まれていない場合に起こります｡
つまり､ データを返すのを忘れていたんですね｡
関数が正しく定義されておらず､ 関数宣言の前にデータ型を削除する必要があるか､
または return 文を追加するのを忘れているかです｡
この警告を修正するためには､
どちらか一方を変更する必要があります｡
しかし､ これが警告であることはおわかりいただけたでしょうか｡ そこでコンパイルすることもできますが､
その場合､ プログラムのカットに問題が生じる可能性があります｡
あなたが何かを返すために関数を期待していると､ それがないので､ あなたの警告未使用の変数別の一般的な警告を修正したい場合｡
これは､ 変数が宣言されたときにコンパイラが表示しますが､ 決して使われることはありません｡
使わない変数は宣言しない方がいいので､
その宣言を削除してください｡
デモをするときに､ 絶対に使わない変数を入れてしまうので､
結構こういうことがあるんです｡
あるいは､ 変数の宣言の仕方を実演していて､ それをコンパイルして見せると､
「それは使われていない」という警告が出たりするんです｡
だから､ それはそれでいいんですよ､ 何かを実証していたわけですから｡ ただし､ 使っていない変数については削除してください｡
宣言する必要はない｡
への未定義の参照｡ これは､ リンクの段階で起こることです｡
だから､ コンパイラやコンパイルの段階を覚えておくと､ コンパイルされる｡
まず､ プリプロセッサを実行し､ 次にオブジェクトファイルを生成し､ そのオブジェクトファイルを取り込んでリンクさせ､
完全なプログラムを作るのである｡
そのため､ リンクの段階で､ 外部の依存関係を解決する必要がある｡
あるいは､ 具体的に呼び出す関数は､ どこかに実装されている必要があります｡
ですから､ そのオブジェクトファイルがないと､ このような問題が発生するのです｡
関数を呼び出そうとしているが､ そのコードがない｡
だから､ このファイルにリンクするようにするか､ どちらかにしなければならない｡
通常､ リンクはあなたのために起こりますが､
GCCでは､ リンクファイルを追加するためにダッシュlオプションを行うだけでよいのです｡
つまり､
mathヘッダーファイルの関数を使用しているのに､ mathオブジェクトファイルにリンクしていない場合､ このエラーが発生するのです｡
また､ ユーザー定義をしていて､ cのソースファイルをインクルードしていない場合にも起こります｡
つまり､ 複数のcのソースファイルがあるわけです｡
cのソースファイルの1つがこの機能を実装しています｡
別のcソースファイルがヘッダをインクルードして呼び出しているのに､
その実装を持つ別のcソースファイルをコンパイルしたことがない場合､
このエラーが表示されます｡
ですから､ そのソースファイルを必ず取り込んでください｡ 必要であれば､
標準ライブラリのソースファイルも取り込んでください｡ 通常は､ その必要はありません｡
もう一つのよくあるエラーは､ forの型が競合している場合です｡
これは､ 実際に関数のプロトタイプを定義したり宣言したりして､ いざ実装しようとしたら､
宣言した方法と違っていた場合です｡
そのため､ 例えばプロトタイプでは､ パラメータに結果型と括弧の名前があり､ その後にセミコロンがあります｡
そして､ 実装を定義するときには､ 実際の関数ヘッダは別のものになります｡
戻り値の型が違うとか､ パラメータの数が違うとか｡
そして､ この関数の宣言が1つある､
ということです｡ そして､ それを下に実装していくとなると､ まったく違うものになります｡
つまり､ ミスマッチがあるんですね｡
そして､ これは実際に､ 矛盾を引き起こした前の定義に現れる線上に表示されます｡
というのも､ 通常､ 関数の宣言は一番上に行いますから､
実装ではその行を表示します｡
ランタイムエラーです｡ ランタイムエラーとは､ コンパイル時ではなく､
プログラムを実行したときに発生するコード上の問題です｡
これらは通常､
クラッシュか､ 配列が境界外にあるなどの非致命的なエラーです｡
プログラムが動いているときに､ 何らかのロジックエラーが発生するんですね｡
そのため､ cプログラムの実行は､ 処理できない実行時エラーが検出されると､ クラッシュして突然終了することがあります｡
先ほど言ったようにメモリが破損しているんです｡
境界外エラーは通常､ プログラムのクラッシュの原因となります｡
通常､ 見えてくるのはセグメンテーションの不具合です｡
そして､ セグメンテーションの断層では何もわからない｡
そこで､ この問題をさらに診断するために､ 一般的にはコールスタックを調べます｡
先ほどプログラムがクラッシュしたと言いましたが､
どの行がクラッシュの原因になっているかを一行ずつ調べていきます｡
先ほどのコアファイルがあれば､ コールスタックを取得することができます｡
そして､ コールスタックから､ どの行がクラッシュしているのかを確認することができます｡
あるいはもっといい方法は､ デバッガを実行して､ 一行ずつステップして､ ある行を実行すると､ デバッガ､
プログラムがクラッシュするのが見えるので､ その方法で特定することです｡
以上､ コンパイラのエラーや警告､ メッセージとその解釈について､
いくつかヒントを挙げてみました｡
実際にネット上にリンクがあります｡
また､
グーグル検索をすれば､ あらゆるコンパイラーエラーや警告が表示され､
なぜそのようなエラーが発生したのか､ 何が問題だったのか､
といった定義が表示されます｡
なぜなら､ これらのコンパイルエラーは､ 非常に不可解なものである場合があるからです｡
そして､ その一言にも､ 手の届かないコントロールが書かれていた｡
この説明から､
経験者でない限りは､ ああ､ 関数から何かを返すことはないんだな､ とわかると思います｡
しかし､ もしそうなら､ コンパイラのエラーがあり､ そのコンパイラを理解していないときに､
プログラムの問題を発見し修正する最良の方法の1つは､ グーグルすることです｡
そして､ 一般的には､ スタックオーバーフローにアクセスすることになります｡
そして､ これはあなたのエラーです､ これを解決するにはどうしたらよいかを教えてくれます｡
今もそうしています｡
私は15年間cでプログラミングをしていますが､ いまだに「これは一体どういうことなんだろう」と思うことに遭遇することがあります｡
ググってみると､ コンパイラを引用符で囲んで､ 何が起こっているのかを正確に教えてくれるんです｡
Stack overflowは､ 本当に､ 本当に良いサイトです｡
そして､ デバッグの時間を大幅に短縮することができるのです｡
コンパイラや警告を見ただけで推測しようとするのはやめましょう｡
そのコンパイラは何かを伝えようとしていて､ 正確にピンポイントに教えてくれるのです｡
だから､ それを理解すれば､ もっともっと早く問題を解決できるようになるんだ｡
そして､ もしそれが馴染みのないものであれば､
stack overflowに行くか､ それらすべてを解説しているウェブサイトに行けば､
そのように解読することができます｡
参考になったでしょうか｡ ありがとうございます｡