c errors undefined reference
このチュートリアルでは、プログラマーがC ++のような未定義の参照、セグメンテーション違反(コアダンプ)、および未解決の外部シンボルで頻繁に遭遇する重大なエラーについて詳しく説明します。
C ++で頻繁に発生する、実際に同様に重要な最も重要なエラーについて説明します。時々発生するシステムおよびセマンティックエラーと例外とは別に、プログラムの実行に影響を与える他の重大なエラーも発生します。
これらのエラーは、ほとんどの場合、実行時にプログラムの終わりに向かって発生します。プログラムが適切な出力を提供し、エラーが発生する場合があります。
=> ゼロからC ++を学ぶには、ここにアクセスしてください。
学習内容:
重要なC ++エラー
このチュートリアルでは、C ++プログラマーの観点から重要な3種類のエラーについて説明します。
- 未定義の参照
- セグメンテーション違反(コアダンプ)
- 未解決の外部シンボル
これらの各エラーの考えられる原因と、これらのエラーを防ぐためにプログラマーとして講じることができる予防措置について説明します。
はじめましょう!!
未定義の参照
プログラムにオブジェクト名(クラス、関数、変数など)への参照があり、リンクされたすべてのオブジェクトファイルとライブラリでそれを検索しようとすると、リンカーがその定義を見つけることができない場合、「未定義の参照」エラーが発生します。
したがって、リンカがリンクされたオブジェクトの定義を見つけることができない場合、「未定義の参照」エラーを発行します。定義から明らかなように、このエラーはリンクプロセスの後の段階で発生します。 「未定義の参照」エラーを引き起こすさまざまな理由があります。
これらの理由のいくつかを以下で説明します。
#1)オブジェクトに定義が提供されていません
これが、「未定義の参照」エラーを引き起こす最も単純な理由です。プログラマーは単にオブジェクトを定義するのを忘れています。
次のC ++プログラムについて考えてみます。ここでは、関数のプロトタイプのみを指定し、それをメイン関数で使用しました。
#include int func1(); int main() { func1(); }
出力:
したがって、このプログラムをコンパイルすると、「「func1()」への未定義の参照」というリンカーエラーが発行されます。
このエラーを取り除くために、関数func1の定義を提供することにより、プログラムを次のように修正します。これで、プログラムは適切な出力を提供します。
#include using namespace std; int func1(); int main() { func1(); } int func1(){ cout<<'hello, world!!'; }
出力:
こんにちは世界!!
ウォークラフトプライベートサーバーの最高の世界
#2)使用されているオブジェクトの誤った定義(署名が一致しない)
「未定義の参照」エラーのさらに別の原因は、間違った定義を指定した場合です。プログラムで任意のオブジェクトを使用しますが、その定義は異なります。
次のC ++プログラムについて考えてみます。ここでは、func1()を呼び出しました。そのプロトタイプはintfunc1()です。しかし、その定義はそのプロトタイプと一致しません。ご覧のとおり、関数の定義には関数のパラメーターが含まれています。
したがって、プログラムがコンパイルされると、プロトタイプと関数呼び出しが一致するため、コンパイルは成功します。しかし、リンカが関数呼び出しをその定義にリンクしようとすると、問題が検出され、「未定義の参照」としてエラーが発行されます。
#include using namespace std; int func1(); int main() { func1(); } int func1(int n){ cout<<'hello, world!!'; }
出力:
したがって、このようなエラーを防ぐために、すべてのオブジェクトの定義と使用法がプログラムで一致しているかどうかをクロスチェックするだけです。
#3)オブジェクトファイルが適切にリンクされていない
この問題により、「未定義の参照」エラーが発生する可能性もあります。ここでは、複数のソースファイルがあり、それらを個別にコンパイルする場合があります。これを行うと、オブジェクトが適切にリンクされず、「未定義の参照」が発生します。
次の2つのC ++プログラムについて考えてみます。最初のファイルでは、2番目のファイルで定義されている「print()」関数を使用します。これらのファイルを個別にコンパイルすると、最初のファイルはprint関数の「未定義の参照」を提供し、2番目のファイルはmain関数の「未定義の参照」を提供します。
int print(); int main() { print(); }
出力:
int print() { return 42; }
出力:
このエラーを解決する方法は、両方のファイルを同時にコンパイルすることです( 例えば、 g ++を使用して)。
すでに説明した原因とは別に、次の理由により「未定義の参照」が発生する場合もあります。
#4)間違ったプロジェクトタイプ
VisualStudioなどのC ++ IDEで間違ったプロジェクトタイプを指定し、プロジェクトが予期しないことを実行しようとすると、「未定義の参照」が発生します。
#5)ライブラリなし
プログラマーがライブラリパスを適切に指定していないか、完全に指定し忘れている場合、プログラムがライブラリから使用するすべての参照の「未定義の参照」を取得します。
#6)依存ファイルがコンパイルされない
プログラマーは、プロジェクトをコンパイルするときにコンパイラーがすべての依存関係を見つけて正常にコンパイルできるように、プロジェクトのすべての依存関係を事前にコンパイルする必要があります。依存関係のいずれかが欠落している場合、コンパイラーは「未定義の参照」を提供します。
上記の原因とは別に、「未定義の参照」エラーは他の多くの状況で発生する可能性があります。しかし、肝心なのは、プログラマーが問題を抱えているということです。このエラーを防ぐには、修正する必要があります。
C ++の単純な二分木プログラム
セグメンテーション違反(コアダンプ)
「セグメンテーション違反(コアダンプ)」というエラーは、メモリの破損を示すエラーです。これは通常、考慮しているプログラムに属していないメモリにアクセスしようとしたときに発生します。
セグメンテーション違反エラーが発生する理由のいくつかを次に示します。
#1)定数文字列の変更
定数文字列を宣言した次のプログラムについて考えてみます。次に、この定数文字列を変更しようとします。プログラムを実行すると、出力にエラーが表示されます。
#include int main() { char *str; //constant string str = 'STH'; //modifying constant string *(str+1) = 'c'; return 0; }
出力:
#2)ポインターの間接参照
ポインタは、逆参照する前に有効なメモリ位置を指している必要があります。以下のプログラムでは、ポインタがNULLを指していることがわかります。これは、ポインタが指しているメモリ位置が0、つまり無効であることを意味します。
したがって、次の行でそれを逆参照するとき、実際にはその未知のメモリ位置にアクセスしようとしています。これは確かにセグメンテーション違反になります。
#include using namespace std; int main() { int* ptr = NULL; //here we are accessing unknown memory location *ptr = 1; cout << *ptr; return 0; }
出力:
セグメンテーション違反
次のプログラムも同様のケースを示しています。このプログラムでも、ポインタが有効なデータを指していません。初期化されていないポインタはNULLと同じくらい良いので、未知のメモリ位置も指します。したがって、それを逆参照しようとすると、セグメンテーション違反が発生します。
#include using namespace std; int main() { int *p; cout<<*p; return 0; }
出力:
セグメンテーション違反
このようなエラーを防ぐために、プログラム内のポインタ変数が常に有効なメモリ位置を指していることを確認する必要があります。
#3)スタックオーバーフロー
プログラムに再帰呼び出しがあると、それらはスタック内のすべてのメモリを使い果たし、スタックをオーバーフローさせます。このような場合、スタックメモリの不足も一種のメモリ破損であるため、セグメンテーション違反が発生します。
数値の階乗を再帰的に計算する以下のプログラムについて考えてみます。基本条件は、数値が0であるかどうかをテストしてから、1を返すことに注意してください。このプログラムは、正の数値に対して完全に機能します。
しかし、実際に負の数を階乗関数に渡すとどうなりますか?負の数には基本条件が与えられていないため、関数はどこで停止するかわからないため、スタックオーバーフローが発生します。
これは、セグメンテーション違反を与える以下の出力に示されています。
#include using namespace std; int factorial(int n) { if(n == 0) { return 1; } return factorial(n-1) * n; } int main() { cout< 出力:
セグメンテーション違反(コアダンプ)
このエラーを修正するために、基本条件を少し変更し、以下に示すように負の数の場合も指定します。
#include using namespace std; int factorial(int n) { // What about n <0? if(n <= 0) { return 1; } return factorial(n-1) * n; } int main() { cout<<'Factorial output:'< 出力:
階乗出力:1
これで、セグメンテーション違反が処理され、プログラムが正常に機能することがわかります。
未解決の外部シンボル
未解決の外部シンボルは、リンクプロセス中にシンボルまたはその参照が見つからないことを示すリンカーエラーです。エラーは「未定義の参照」に似ており、交換可能に発行されます。
セレンjavaインタビューの質問と回答
このエラーが発生する可能性のある2つのインスタンスを以下に示します。
#1)静的メンバーを含むプログラムで構造変数を参照する場合。
#include struct C { static int s; }; // int C::s; // Uncomment the following line to fix the error. int main() { C c; C::s = 1; }
出力:
上記のプログラムでは、構造体Cには、外部プログラムからアクセスできない静的メンバーsがあります。そのため、main関数で値を割り当てようとすると、リンカはシンボルを見つけられず、「未解決の外部シンボル」または「未定義の参照」になる可能性があります。
このエラーを修正する方法は、変数を使用する前に、メインの外側で「::」を使用して変数を明示的にスコープすることです。
#2)ソースファイルで参照されている外部変数があり、これらの外部変数を定義するファイルをリンクしていない場合。
このケースを以下に示します。
#include #include using namespace std; extern int i; extern void g(); void f() { i++; g(); } int main() {}
出力:
一般に、「未解決の外部シンボル」の場合、関数などのオブジェクトのコンパイル済みコードは、参照先のシンボルを見つけることができません。おそらく、そのシンボルがオブジェクトファイルまたはライブラリで定義されていないためです。リンカーに指定されます。
結論
このチュートリアルでは、C ++のいくつかの主要なエラーについて説明しました。これらは重大であり、プログラムフローに影響を与える可能性があり、アプリケーションのクラッシュにつながる可能性もあります。セグメンテーション違反、未解決の外部シンボル、および未定義の参照について詳しく調べました。
これらのエラーはいつでも発生する可能性がありますが、説明した原因から、プログラムを注意深く開発することで簡単にエラーを防ぐことができることがわかります。
=> Easy C ++トレーニングシリーズをお読みください。
推奨読書