[解決済み] C: リンカーコマンドが失敗し、終了コード 1 が表示されました。
質問
コードをコンパイルするときに問題があります。エラーメッセージは出ていません。しかし、次のようなメッセージが表示されます。
Undefined symbols for architecture x86_64:
"_lookup", referenced from:
_main in sixteen2-85c27c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
私は今までこのようなものに遭遇したことがなく、私がオンラインで見つけることができる情報のほとんどは、プレーンCではなく、Objective-Cに関係しています。
以下は私のコードです。
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]) {
struct entry {
char word[15];
char definition[100];
};
const struct entry dictionary[100] =
{{"aardvark", "a burrowing African mammal"},
{"abyss", "a bottomless pit"},
{"acumen", "mentally sharp; keen"},
{"addle", "to become confused"},
{"aerie", "a high nest"},
{"affix", "to append; attach"},
{"agar", "a jelly made from seaweed"},
{"ahoy", "a nautical call of greeting"},
{"aigrette", "an ornamental cluster of feathers"},
{"ajar", "partially opened"}};
int entries = 10;
int entryNumber;
int lookup (const struct entry dictionary[], const char search[], const int entries);
if (argc != 2)
{
fprintf (stderr, "No word typed on the command line.\n");
return EXIT_FAILURE;
}
entryNumber = lookup (dictionary, argv[1], entries);
if (entryNumber != -1)
printf("%s\n", dictionary[entryNumber].definition);
else
printf("Sorry, %s is not in my dictionary.\n", argv[1]);
return EXIT_SUCCESS;
}
解決方法は?
次のようなコード行がありますね。
int lookup (const struct entry dictionary[], const char search[], const int entries);
main関数の内部です。 これには2つの大きな問題があります。
-
関数宣言は、他の関数の中に記述することはできません。 私が引用した行は、以下のようにmain関数の外側に表示する必要があります。
int lookup(.....) //code here int main(...) { //more code here }
-
関数 "lookup" を宣言しているにもかかわらず、決して 定義 です。 これがリンカーエラーの原因になっていると思われます。 コンパイラがすべての関数をコンパイルし、リンカがその関数を(いわば)リンクしようとしたところ、関数 "lookup" が宣言され、後で呼び出されてはいるものの、実際にはどこにも存在しないことがわかったのです! (私の知る限り、関数 "lookup" は stdlib.h や stdio.h には存在しません). このため、リンカはその仕事をすることができません。
要約すると、あなたのコードは以下のように再編成されるはずです。
#include <stdio.h>
#include <stdlib.h>
int lookup (const struct entry dictionary[], const char search[], const int entries)
{
//lots of code belongs in here, but that's for you to figure out :)
}
int main (int argc, char *argv[]) {
struct entry {
char word[15];
char definition[100];
};
const struct entry dictionary[100] =
{{"aardvark", "a burrowing African mammal"},
{"abyss", "a bottomless pit"},
{"acumen", "mentally sharp; keen"},
{"addle", "to become confused"},
{"aerie", "a high nest"},
{"affix", "to append; attach"},
{"agar", "a jelly made from seaweed"},
{"ahoy", "a nautical call of greeting"},
{"aigrette", "an ornamental cluster of feathers"},
{"ajar", "partially opened"}};
int entries = 10;
int entryNumber;
//**REMOVE THIS LINE** Move it up top....
//int lookup (const struct entry dictionary[], const char search[], const int entries);
if (argc != 2)
{
fprintf (stderr, "No word typed on the command line.\n");
return EXIT_FAILURE;
}
entryNumber = lookup (dictionary, argv[1], entries);
if (entryNumber != -1)
printf("%s\n", dictionary[entryNumber].definition);
else
printf("Sorry, %s is not in my dictionary.\n", argv[1]);
return EXIT_SUCCESS;
}
お役に立てれば幸いです。 もし、リンカーが何をするものなのか、なぜこれが重要なのか理解できない場合は、コメントを残していただければ、それに応じて私の答えを編集します。 リンカーとコンパイラーを理解することは、平凡なCプログラマーと偉大なCプログラマーを分ける多くの要因の1つです!
この際、リンカーとは何かということを説明するのも有効だと思います。 しかし、その前に、コンパイラが何をするのか、そして、コンパイルされたプログラムが本当は何なのかを理解することが重要なのです。
質問に投稿されたコードから、あなたはコンパイラーを複数回使用したことがあると推測してよいと思います :). あなたがすでに知っていることをいくつか言いますが、お付き合いください。 あなたが持っている ".c" と ".h" ファイルは、アルゴリズムを記述したものです。 これらのファイルは人間が読んだり編集したりするのは簡単ですが、コンピュータがそこから意味を抽出するのは難しいのです。 コンピュータがこれらのファイル内のプログラムを実行するためには、アルゴリズムをコンピュータが理解できる言語に変換する必要があります。 機械語」と呼ばれるこの言語は、人間が書くには難しいので、CやC++で書き、コンパイラーを使ってCやC++のプログラムを「機械語」に変換しているのです。
さて、ここでのリンカーの働きは微妙ですが、非常に重要です。 初心者は、リンカーは全く必要ないと思いがちです。コンパイラーがC言語を機械語に変換してくれれば、それで仕事は終わりですからね。
コンパイルされたプログラムの中の機械語には、メモリアドレスがあります。 次のようなおもちゃのような例を考えてみてください。
#include <stdio.h>
int addnums(int numbers[], int length)
{
int total = 0;
for(int i = 0; i < length; i++)
{
total += numbers[i];
}
return total;
}
int main(int argc, char** argv)
{
int mynums[] = {1, 2, 3, 4, 5};
int total = addnums(mynums, 5);
printf("the total of the array is %i\n", total);
return 0;
}
このおもちゃのプログラムの機械語コードを見てみると、各関数はコンピュータのメモリ上に始点と終点を持っていることがわかるだろう。 つまり、各関数には アドレス で始まる。 コンピュータがこの行を実行すると
int total = addnums(mynums, 5);
int main()" はアドレス100で始まり、int addnums()" はアドレス50にあるとします。 コンピュータは、この行に到達したら、アドレス50のマシン・コードを実行する必要があります。
コンパイラは関数のアドレスは気にしません。 ただコンパイルするだけで、正しいアドレスをマシンコードに書き込むのは別のプログラムに任されています。 もしリンカが次のようなことを言ったら
symbol(s) not found
は、リンカがある関数のアドレスを知らないことを意味します。 これは通常、問題の関数が一度も宣言または定義されていないことが原因です。 このコードから実行ファイルを作成すると、コンピューターは次のような行に到達します。
int total = addnums(mynums, 5);
int addnums() "関数にジャンプするアドレスがなければ、あなたのCPUは完全に迷子になってしまうでしょう。
を実行すると、プログラムが不思議なことにクラッシュしてしまいます。
リンカはエラーを出してコンパイルを止めるので、この心労を軽減することができます。 素人時代に組み込みシステムのプログラミングをしていたとき、この問題に何度か遭遇し、デバッグするのが悪夢のようでした。
お役に立てれば幸いです。 もし私の説明が悪かったら教えてください。
関連
-
[解決済み】valgrind - サイズ8のブロックが割り当てられた後、アドレス ---- が0バイトになる。
-
[解決済み】エラー:イニシャライザー要素がロード時に計算可能でない
-
[解決済み】Cygwin - Makefile-error: ターゲット `main.o' のレシピに失敗しました。
-
[解決済み】C 未知の型名「my_structure」。
-
[解決済み】C言語で入力が整数型かどうかチェックする
-
[解決済み】警告:引数「互換性のないポインタ型から」を渡す[デフォルトで有効]。
-
[解決済み】エラー:呼び出されたオブジェクトは、関数または関数ポインタではない
-
[解決済み] C言語のコードで「:-!」とは何ですか?
-
[解決済み] 配列の場合、なぜ a[5] == 5[a] になるのでしょうか?
-
[解決済み] 難読化Cコードコンテスト2006。sykes2.cの解説をお願いします。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Valgrind - strcpyのサイズ1の無効な書き込み
-
[解決済み】単項演算子「*」の型が無効(「int」がある)C言語でのエラー
-
[解決済み】 error: too few arguments to function `printDay' (C言語)
-
[解決済み】初期化がキャストなしで整数からポインタを作成 - C言語
-
[解決済み】Cygwin - Makefile-error: ターゲット `main.o' のレシピに失敗しました。
-
[解決済み] struct で "warning: useless storage class specifier in empty declaration" (警告: 空の宣言での無駄なストレージクラス指定子)
-
[解決済み] テスト
-
[解決済み】sizeof float (3.0) vs (3.0f)
-
[解決済み] エラー:整数が期待されるところで集約値が使用された
-
[解決済み】Linuxソケットのwrite()でBad File Descriptorが発生するC