こんにちは､ ようこそ｡
この講義では､ デバッグについてお話したいと思います｡
これは非常に重要な概念で､ 具体的には､ バグを発見し修正するために採用できるツールや方法のいくつかを理解する必要があります｡
つまり､ デバッグとは､ プログラムのエラーを発見し､ 修正する作業なのです｡
通常､ ロジックエラーです｡
そして､ ロジックエラーとシンタックスエラーの違いをお伝えしますが､ コンパイラのシンタックスエラーも含まれることがあります｡
シンタックスエラーのための全工程です｡
デバッグとは､ コンパイラが何を言っているのかを理解することです｡
常に最初に検出された問題を解決することに集中したいものです｡
よくあるコンパイラのエラーや警告をいくつか見ていきたいと思いますが､ コンパイラについて常に知っておきたいことのひとつが､
コンパイラがさまざまなエラーを出すことがあるということです｡
その最初のエラーが他のエラーを引き起こす可能性があるため､ 常に最初のエラーに焦点を当てたいのです｡
そのため､ コンパイラが教えてくれるプログラムの中に5つのエラーがあると､ 非常に誤解を招きやすいのですが､ エラーは1つだけで､
その最初のエラーが他のエラーを引き起こしている可能性があります｡
だから､ 常に最初のトップのエラーを見て､ まずそれを修正することが重要なんです｡
この非常に単純な例では､ このコードに複数のエラーが発生しています｡
を持っていない｡
冒頭の左括弧､ 中括弧がないんです｡
セミコロンがないんです｡
文字列を返しています｡
そして､ これを保存してコンパイルしようとすると､ 赤いエラーがいくつか表示されるのですが､
コンパイルしようとすると､ 実際には3つのエラーがあると表示されます｡
この場合､ 実際のエラーであるにもかかわらず､ 7行目の最後のエラーだけを選択することは絶対に避けたい｡
いつも最初のエラーだけ直したいと思ってしまう｡
そこで､ ここに記載されている最初のエラーを見て､ その最初のエラーを修正し､ 再コンパイルして再度実行します｡
しかし､ このようなことをするのは､ そのトップレベルのエラーを修正するためだけで､ そのエラーが他の問題を引き起こすかもしれないからです｡
そのため､ 常に最初のエラーを修正することに集中します｡ バグの発見と修正のプロセスは､ 単純なエラーの発見から分析のための大量のデータ収集まで､
非常に複雑になる可能性があります｡
全ては人それぞれです｡
ロギング以外の情報が提供されていないこともあり､ その場合はいろいろと分析する必要がありますね｡
繰り返し再現性のないバグが発生することもありますよね｡
そんな稀有なことが起こるから､ 再現できないんですね｡
それは通常､ ログの解析やその何らかのバリエーションが必要な場合です｡
プログラマーによるデバッグ能力は必須スキルです｡
まさに､ 時間とお金を圧倒的に節約できる問題解決スキルなのです｡
だから､ 大切なスキルなんです｡
大切なスキルとして身につけることができます｡
練習が必要です｡
あなたは､ それがあなたのところに来るだけではないのです｡
デバッグを上手にするために､ 応用できるテクニックや方法があるのです｡
私は､ ソフトウェアを書くコードを書くのが得意な開発者をかなり多く知っています｡
彼らは言語を非常によく理解していますが､ デバッグのスキルは非常に低いのです｡
バグを発見し､ そのバグを解決するために最初に思いついたことが､ 本当に道を踏み外すことになるかもしれません｡
そしてまた､ これは練習が必要です｡
デバッグや問題の見つけ方､ 直し方を理解することで､ どんどん上達していきますが､ それは自分も身につけなければならないことですからね｡
保守フェーズは､ ソフトウェアのライフサイクルの中で最もコストがかかるフェーズです｡
メンテナンスフェーズは､ 製品をリリースした後､ 今度はそれを維持する必要があります｡
メンテナンスとは､ 新たに発生したバグを修正したり､ 新機能を追加したりすることです｡
ですから､ 例えばWindowsがWindows 10のような新しいOSをリリースしても､ そのソフトの生産は終わっていません｡
おそらく10年ぐらいは野ざらしになるんでしょうね｡
そして､ そのソフトウェアに新しいバグが入ったり､ 新しいバグが見つかったりした場合､ それを修正するのはやはりマイクロソフトの責任です｡
そのため､ 自動更新をプッシュしたり､ そのようなことをするのです｡
そして､ 市場の変化や技術の変化に応じて､ オペレーティングシステムが新しい機能を提供することにも気づかれるでしょう｡
だから､ メンテナンスはとても大切なんです｡
そして､ その結果､ バグを発見し､ 修正することがとても重要になります｡
しかし､ バグは避けられないものであることを理解してください｡
すべてのソフトウェアにはバグがあります｡
完璧なコードを書ける人はいませんし､ 必ずしも完璧なコードを書くことが目的でもありません｡
ただ､ 時代とともに変化していくものです｡
そのため､ 結果的にバグが発生することもあります｡
ソフトウェアにバグがあるからといって､ それが粗悪なコードであるとは限らないことを理解する必要があります｡
なんだか､ やむを得ないですね｡
だから､ バグがあってもいいんです｡ バグを見つけて直したときは､ 何かを達成したような気がして､
さらにうれしいですね｡
よくある問題｡
そして､ シーにまつわる具体的な問題について､ より詳しくお話しします｡
しかし､ デバッグをしようとするときによくある問題は､ ロジックエラーです｡
ロジックエラーは､ あなたのコードが実際にコンパイルされるシンタックスエラーの種類の反対とは関係ありません｡
機能するけど､ 意図したとおりにならない｡
つまり､ 何らかのロジックや意図した機能が間違っているのです｡
もしかしたら､ IF文があって､ そのIF文に間違った条件で飛び込んでいるのかもしれません｡
ループがあって､ そのループが正しい回数実行されていないか､ 正しくソートされていないのかもしれませんね｡
機能は壊れていますが､ コンパイラは「おい､ 全部うまくいっているぞ」と言います｡
ロジックエラーの一例を紹介します｡
論理エラーとは､ 構文は正しいが､ 何らかの論理的な問題により､ 望ましい結果が正しく得られないことである｡
つまり､ このコードでは､ forループの最後にセミコロンがあり､ 構文的に正しいことがわかります｡
しかし､ このforループが5回実行されることを想定しているのですね｡
でも､ そうではないんです｡
1回の走行時間しかないんです｡
このプロジェクトをビルドすると､ 警告が表示されるのですが､ これはいいことです｡
しかし､ 正常にコンパイルできました｡
このプロジェクトを実行すると､ 実際には1回しか実行されず､ Hello Worldが1回表示されることに気づくはずです｡
つまり､ これはロジックエラーの一例なのです｡
構文エラーはコンパイラに直接関係するものです｡
これらは､ 言語のルールに則っていないことです｡
文の最後にセミコロンがないんですね｡
エンディングはないんでしょう？
左で括弧､ 括弧｡
ブラケットが足りません｡
キーワードの使い方が間違っている､ そんな感じです｡
シンタックスエラーは通常､ コンパイラによって引き起こされる 論理エラーはテスト段階でプログラマによって引き起こされることになる｡
メモリ破壊も､ 特にC言語ではよくある問題です｡
メモリを正しく割り当てた後に解放していないと､ ぶら下がり参照のようなものが発生したり､
使用されていないメモリに関連するメモリ問題が発生したりする可能性があります｡
メモリリークを起こすことができる｡
ここでは､ メモリエラーの例を紹介します｡
このコードでは､ 実際にメモリリークが発生しているので､ ポインタの話はまだしていません｡
動的メモリ割り当ての話はしていない｡
しかし､ C言語では､ プログラムの実行中にメモリを確保することができます｡
malloc関数を使用することができます｡
メモリは確保されているが､ 解放されることはない｡
つまり､ このコードをビルドし､ 実行すればすべてうまくいくのですが､ 実際にはこのエラーを解放しているわけではありません｡
つまり､ このメモリエラーを修正するためには､ free と言ってから､ free と X を言ってそのポインタを解放しなければならないのです｡
しかし､ メモリを確保するときは必ず解放するわけではありません｡
それはメモリリークです｡
そして､ もう一つの例として､ メモリを割り当てない場合､ ポインタを作成してそれを割り当てようとすると､
そのメモリには割り当てがなく､ それに値を割り当てようとするため､ メモリ破壊が発生することになります｡
これは､ メモリ､ 破損､ パフォーマンス､ スケーラビリティに関するいくつかの例を少し紹介したに過ぎません｡
これは､ 機能はそのまま意図しているし､ コードも構文的には正しいが､ 効率が悪かったり､ それをサポートするハードウェアを持っていなかったりする問題かもしれません｡
ですから､ サーバーを運用していて､ すべてのリクエストをサポートするのに十分なハードウェアがない場合､
動作は本当に､ 本当に遅くなります｡
あるいは､ 10人のユーザーで動くようにプログラムを書いたのに､ ユーザーが多くなると､ データベースが詰まるから速くならないとか､
そういうケースもあるかもしれませんね｡
コードは機能するが､ 何人もの大量のユーザーを処理するために正しく設計されていないとか､ そういうことがある｡
まとまりがない｡
これは､ コードがやりすぎていたり､ 関数がやりすぎていたりして､ 品質が低下していることに関連するコードの問題である可能性があります｡
一点集中でもなく､ アプリケーションも機能が多すぎたり､ 使わない機能があったりして､
これでは設計のやり直しが必要でしょう｡
モジュール化されていない､ まとまりのないプログラムになってしまう例を紹介します｡
1つの大きな関数が､ 何百行､ 何千行ものコードで､ あまりにも多くのことを行っているのです｡
ある機能をヘルパー機能､ 別モジュールに分解したい｡
そうすることで､ プログラムのまとまりがよくなり､ メンテナンスがしやすくなります｡
つまり､ 初期化､ 入力の読み取り､ 一部の検索､ 差の検索､ 積の検索､ 商の検索を行う大きなメインメソッドを持つ代わりに､
これらのコードをすべて作成してヘルパーモジュールに置き､ コードを分離することで､
バグの発見と修正をより簡単に行うことができるのです｡
C言語では常に凝集性が重要であり､ 凝集性が高いところはヘルパーメソッドを提供することで解決するのが普通です｡
タイトなカップリング｡
これは､ コードの品質にも関係しています｡
ここは､ 依存関係が多いところですね｡
カップリングはコヒーシオンとは異なります｡
コヒーシオンがあなたの一点集中｡
カップリングとは､ 機能間やオブジェクト間に依存関係を持たせることです｡
カップリングの話もしたし､ グローバル変数の話もした｡
グローバル変数の変数が多くの異なる機能で使用されている場合､ それらの機能間で依存関係が発生する可能性があります｡
つまり､ コードを書くときに､ 高品質のコードを書くために努力したいことは､
非常に高い凝集性と非常に低い結合性を持つことです｡
デバッグの様子です｡
どのようなエラーであっても､ それを発見し修正する前にまずやらなければならないことは､ 問題を理解することです｡
これは､ ただ飛び込んでコードを見始めるのではなく､ テスターと一緒に座って､ 要件を理解し､ 何が起こっているのかを理解することと関連しています｡
だって､ 何が起こっているのか理解できていなければ､ それすらできないのですから｡
解こうとするのもやめたほうがいい｡
バグを理解したら､ バグを再現することで､ より多くの情報を集めることができるので､ 再現してみてください｡
バグは本当に稀な状況で発生する可能性があるため､ 必ずしも再現できるわけではありません｡
例えば､ レースコンディションやメモリ破壊のようなバグは､ 非常に特殊なユースケースでしか発生せず､
断続的な問題である可能性があるわけです｡
といったところでしょうか？
しかも再現できない｡
これからどんどんデバッグが難しくなっていきますね｡
再現できれば､ たいていの場合､ 修正するのに十分な情報を集めることができます｡
ほとんどの問題は解決可能です｡
また､ マルチスレッド環境､ 並列処理､ スレッドの問題がある場合､ 再現できない問題が発生することがあります｡
デバッグも非常に難しいのですが､
実際に何が問題なのかを理解した上で､
再現してみてください｡
バグを分離し､ 問題を単純化することを試みます｡ なぜなら､ 縮小することで情報が戻ってきますが､
バグがコードのどの部分にあるのかがわかるとは限らないからです｡
そこで､ 問題を単純化するためにできることは､ 元のテストケースの一部を削除して､ テストし過ぎないようにすることです｡
ああ､ この特定の状況でしか起きないんだ」と､ 問題をさらに小さく切り分けることができるのです｡
また､ コードをコメントアウトすることもできます｡
関数はスタブを持つだけで実装を持たないという話をしました｡
それがテストで採用されることもあるので､ 問題セットを限定することができるのです｡
また､ コードをコメントアウトすれば､ バグが実際に起こりうるコードが少なくなります｡
そのため､ コードをコメントアウトしたり､ 変更を取り消したりしているうちに､ バグがなくなるかもしれません｡ バグがなくなれば､
コメントアウトしたコードが原因だった可能性があるということです｡
しかし､ あなたが本質的にやりたいことは､ テストやコメントアウトによって､ 大きなプログラムを多くの小さなプログラムに変えることです｡
もう一つの一般的なテクニックは､ コードの周りにユニットテストを持つことです｡
ユニットテストが失敗すれば､ コードのどこにロジックや問題があるのかが正確にわかります｡
バグを切り分ければ､ コードの中にある問題の原因､ つまり問題を引き起こしている特定のコードを見つけるのに役立ちます｡
そのため､ デバッガーなどのデバッグツールを使うこともあります｡
これから具体的にデバッガの話をしますが､ 通常､ どのようなIDE統合開発を使っているかによって､
IDEに付属しているデバッガがあるんです｡
スタンドアロンで着地できるデバッガーもある｡
C言語プログラミングで使う大きな重要なデバッガは､ GDBと呼ばれるものです｡
GNUデバッガーは､ プログラムの実行を停止したり､ ブレークポイントを追加したりできるグラフィカルなツールで､
とても便利です｡
そして､ 実行を止めると､ コードを1行ずつ見ていき､ 変数の値を見ることができます｡
そのため､ 実行中のコードで何が起こっているのかを正確に把握することができます｡
貴重なツールです｡
とにかく便利なんです｡
デバッガで実行します｡
ブレークポイントの付け方を紹介します｡
変数の変化を見ることができるようにウォッチを設定する方法を紹介し､ さらにその後にコードを踏み込んで説明します｡
問題の原因を特定したら､ 次はそれを解決しなければならない｡
これには､ 多くの経験と練習が必要です｡
問題の原因がわかったからといって､ やはり経験値だけで解決できるとは限りません｡
これは､ 特にスケーラビリティの問題やパフォーマンスの問題で､ ソフトウェアがよりスケーラブルになるように再設計する必要があるかもしれない､
他のコードの再設計やリファクタリングを含むことがあります｡
だから､ 問題を発見し､ それを解決することだけが簡単なことではないのです｡
特にスレッディングや並列処理など､ より一層難しい問題が時々発生するのですが､ それらは解決するのがさらに困難です｡
しかし､ コードをどんどん書いていくうちに､ これが簡単にできるようになっていきます｡
そして最後に､ 狂ったようにテストすることだ｡
常に様々な境界線をテストする｡
良いケースと悪いケースの中間で､ 本当に問題を解決できたかどうかを検証します｡
そのテクニックやツールの一部をご紹介します｡
一般的で､ とてもとても使われるツールに､ print文の利用があります｡
print文を使って､ 基本的にコードをトレースすることができます｡
だからC言語ではprint Fステートメントを使うことができ､ コードの複数の行に置いて､ どこにいるのかを示すことができるのです｡
これは､ プログラムがクラッシュしたときにも便利で､ とても役に立ちます｡
クラッシュした場所を特定するのに役立ちます｡
変数の値が状態に影響を与え､ ロジックの問題を引き起こしている可能性があるからです｡
だから､ print文を追加するだけで､ とてもとても便利です｡
実行の流れを示すことができ､ エラーの切り分けに役立ちます｡
デバッガは､ GDBで紹介したように､ プログラムの実行を監視することができます｡
停止させたり､ 一行ずつ実行したり､ 再起動させたり､ ブレークポイントを設定したり､ 変数やメモリを見たりすることができます｡
問題がどこにあるのかを診断するときに､ とてもとても役に立ちます｡
ログファイルです｡
ログファイルも､ 特に再現性のないバグには非常に有効です｡
後日､ 解析することで､ バグが発生したときの状況を正確に把握することができます｡
つまり､ これを利用するためには､ コード自体にしっかりとしたロギング文を用意する必要があるということですね｡
そこで､ 独自のログファイルを作成し､ プログラムの実行中にそのログに書き込み､ エラーが発生した場合に､ そのログを開発者に送信できるようにすることができます｡
ゼロックスでは､ 問題が発生したときに再現できないことがあったり､ 現場で遭遇することがあるので､
これをかなり採用しています｡
そのバグが起きたときに何が起きていたのか､ そのログにアクセスできるようにする必要があるのです｡
モニタリングソフトです｡
メモリ使用量､ ネットワークトラフィックの脅威､ オブジェクト情報などを監視し､ 実行時に分析できるソフトウェアがあります｡
これは､ もしかしたらメモリを過剰に割り当て､ それを削除していないかもしれないことを教えてくれるものです｡
もし､ メモリ使用量のネットワークトラフィックを調べるツールがあれば､ パケットを送りすぎていないか､
ソフトウェアのスケーラビリティはどうか､ ネットワークトラフィックが増加した場合､ 応答時間が低下していないかなどを知ることができます｡
また､ 並列処理のためのスレッドやオブジェクトの情報を監視して､ あるスレッドで何が起こっているのか､ 別のスレッドで何が起こっているのかを確認することができます｡
それが､ あらゆるスレッドの種類の問題を診断するのに役立つのです｡
その他､ エラーを発見し修正するために採用できる一般的なデバッグツールもあります｡
例外処理を使用することができます｡
多くのプログラミング言語が例外処理を備えています｡
残念ながら､ C言語では例外ハンドラは実際にクラッシュを防ぎ､ 実行時に多くのことを行うことはできません｡
見るには当てはまらないが､ やはり理解しておくに越したことはない｡
Trycatchブロックとかね｡
スタティックアナライザーです｡
C言語の静的解析ツールには､ 多くの静的解析ツールが用意されています｡
実際の実行ファイルがない状態でソースコードを解析する｡
プログラムの実行は､ 実行する必要はありません｡
一行ずつ進んで､ ソースコードを見るのです｡
そして､ ソースコードを解析する際に､ 既知の問題がないかどうかを調べます｡
だから､ セマンティクスをチェックすることができる｡
確認することができます｡
それでいいじゃないですか｡
新しいメモリを確保するときに､ それを削除するのであれば､ 未初期化の変数はありません｡
コードが実際に実行されていないデッドコードがあれば､ そのコードを削除することができます｡
また､ レースコンディションやデッドロックといったことも解析します｡
私の職場でも､ 静的解析機を数台採用しています｡
また､ コードソナーというツールもありますが､ これもよく使われています｡
そして､ 新しいファイルや新しいコードを導入するたびに､ そのコードに対してこのツールを実行し､ 未初期化変数やメモリリークなど､
コードの問題を即座に特定することができるようになるのです｡
シンタックスの解析は行いません｡
そのためのコンパイラなのです｡
また､ ソフトウェアで実行できる包括的なシステムのエンドツーエンドテストのセットを実行するテストスイートも数多くあります｡
テストは常に重要ですが､ 例えば新しいビルドを行うたびに特定のテストを実行するように自動化できれば､
非常に便利です｡ これは実際にエラーを防ぐことができますが､ エラーの診断にも役立ちます｡
プログラムがクラッシュした後にデバッグする｡
今回はコールスタックと呼ばれるものについてお話します｡
特にC言語のように､ クラッシュしたときにセグメンテーションフォールトのような情報しか得られないような場合､
これは非常に便利な仕組みです｡
クラッシュした場合､ クラッシュの仕方にもよりますが､ 多くの場合､ コアファイルが生成されます｡
コアファイルを解析してコールスタックを調べれば､ プログラムがどこで死んだかを正確に知ることができます｡
プログラムが死んだコード行を教えてくれます｡
それで､ コールスタックについて学びます｡
また､ コアファイルの解析に関しては､ より高度な技術になりますね｡
しかし､ C言語ではコアファイルを生成して､ それを解析することができます｡
これは少し高度なテクニックですが､ ソフトウェアでデバッグを行うためのもう一つの方法です｡
エラーの防止についてはいかがでしょうか？
デバッグはエラーを発見して修正することだとわかっていますが､ エラーを防ぐことができれば､ さらに良いことです｡
エラーを防ぐ方法の1つは､ 高品質のコードを書くことです｡
これは､ 本当に多くのソフトウェアエンジニアが重視していないことです｡
多くのソフトウェアエンジニアは､ コードを書いて､ それが動けばそれでよし､
出力が正しければそれでよしとする｡
しかし､ 質の悪いコードというものがあり､ それを書きたくないというのが本音です｡
講義の中でいくつか実演しましたが､ 意味のある変数名を使うことなどはとても重要です｡
あるいは､ ループを必要以上に使っていたり､ if文を使っていたり､ そんなことをする必要がないような非効率的なコードを書いている場合です｡
これらのタイプはすべて､ 質の低いコードになります｡
もし､ ある関数が他の100のことをしていてまとまりがない場合､ 関数内に5000行もある場合､
コードがモジュール方式で構成されていない場合､ 関数間に多くの依存関係がある場合､
これらすべてが質の低いコードであり､ これをしないよう努力したいものです｡
プログラムが整理されているようなテクニックを採用したい｡
メンテナンスが簡単で､ 結束力が高く､ カップリングが少なく､ 意味のある変数名を使っています｡
とても､ とても重要なことです｡
また､ メンテナンスの段階はとても高価なので､ これもとても重要です｡
質の悪いコードを書くと､ メンテナンスが非常に難しくなります｡
エラーの切り分けが難しくなり､ 新機能の追加も難しくなります｡
だから､ コードを書くときは､ 良い高品質のテクニックを従業員にしてください｡
単体テストです｡
ユニットテストは､ エラーを防ぐのに非常に役立ちます｡
ユニットテストは通常､ コンパイル時に自動的に実行されるため､ リグレッションを回避するのに役立ちます｡
それが最も重要な要素のひとつです｡
回帰とは､ 新しいコードを書いたときに､ それまで動作していたものにバグが発生することです｡
古いコードを壊したのか｡
そんなの嫌でしょう｡
あるソフトウェアが動作しているときに､ 何か新しいことをしたらそれが壊れたとしたら､ すぐにそのことを知らせたいものです｡
ユニットテストは､ その古いコードに対して実行され､ 「これは動作していたが､ 今は失敗している」と教えてくれます｡
また､ 新しいコードが納品される前にエラーを発見することもできます｡
テスト駆動開発というコンセプトがありますが､ これはとても人気があります｡
これは､ 最初にテストを書いて､ その後にコードを開発するものです｡
そして､ ここでのゴールは､ 最初のテストを書いたときに､ テストが失敗していて､ それをパスさせるためのコードを書くことです｡
TDDの利点はたくさんありますし､ 逆の発想のような気もします｡
通常､ 人はコードを書くとき､ まずコードを書き､ その後にテストを書きます｡
しかし､ TDDを使うと､ 本当に小さな塊で作業するようになり､ 非常にまとまりのあるコードを書くようになりますし､
コードや依存関係があまりないようになります｡
コードをテストできるということは､ そのコードにはそれほど多くの依存関係がないということです｡
もしユニットテストがとても大きく､ さまざまなものをモックしているとしたら､ それは通常､
あなたのコードが他のものにとてもとても依存していることを示す大きな指標となります｡
つまり､ TDDを採用することで､ 依存関係のない非常に疎結合なコードを書くことを強制し､ 関数を非常に凝集させることができるのです｡
TDDの利点はたくさんあります｡
また､ ドキュメントをしっかり作成し､ 適切なプランニングを行いたいものです｡
コードに飛び込んで実装を始めるだけではダメだ｡
紙にデザインを書き出す｡
疑似コードを活用する｡
そうですね｡
コードを計画する｡
コードを計画し､ 要件を理解し､ よく考えた設計をすれば､ 多くの､ 多くのエラーを防ぐことができるのです｡
1000行のコードを書いて､ よし､ コンパイルしてテストだ､
というようなことはしないで､ 小さなステップで作業し､ 各ステップで常にテストを行う｡
それは良い方法とは言えません｡
一度に多くの変更を避ける｡
変更を加える場合は､ 段階的に適用し､ 1つの変更を加え､ 次のステップに入る前に十分にテストします｡
これは､ あらゆる種類のバグを減らすことができ､ また､ 問題セットを制限することができます｡
そのため､ もしバグがあったとしても､ コンパイルしてその行を追加しただけなので､
コードのどこにバグがあるのかすぐにわかります｡
繰り返しになりますが､ デバッグの重要性を強調することはできませんが､ 高品質のコードを書くこと､ エラーを防ぐこと｡
これらの問題解決のテクニックは､ あなたの時間を大幅に節約し､ より優れたプログラマートップティアのプログラマになることでしょう｡
そこで､ これから数回の講義で､ プログラミング言語c cでよく見られるエラーについてお話したいと思います｡
また､ コールスタックについて少しお話したいと思います｡
デバッガーでは､ メニューオプションの紹介や､ ウォッチの停止や実行の仕方などを説明したいと思います｡
そして､ 私はまた､ あなたがコンパイラ､ コンパイラの警告とエラーを解釈する方法を参照してくださいいくつかの一般的なコンパイラのエラーを識別するのに役立ちたいと思います｡
コンパイラがこう言っているのは､ どういう意味ですか？
コンパイラがこのような警告を出すのはどういうことでしょうか｡
ありがとうございます｡