92

単純なプログラムですが、このコンパイラエラーが発生し続けます。コンパイラーにMinGWを使用しています。

これがヘッダーファイルpoint.hです:

//type for a Cartesian point
typedef struct {
  double x;
  double y;
} Point;

Point create(double x, double y);
Point midpoint(Point p, Point q);

そしてここにpoint.cがあります:

//This is the implementation of the point type
#include "point.h"

int main() {
  return 0;
}
Point create(double x, double y) {
  Point p;
  p.x = x;
  p.y = y;
  return p;
}

Point midpoint(Point p, Point q) {
  Point mid;
  mid.x = (p.x + q.x) / 2;
  mid.y = (p.y + q.y) / 2;
  return mid;
}

そして、ここでコンパイラの問題が発生します。私は次のことを続けています。

testpoint.c:'create(double x、double y)'への未定義の参照

それはpoint.cで定義されていますが。

これはtestpoint.cと呼ばれる別のファイルです:

#include "point.h"
#include <assert.h>
#include <stdio.h>
int main() {
  double x = 1;
  double y = 1;
  Point p = create(x, y);

  assert(p.x == 1);
  return 0;
}

問題が何であるかについて私は途方に暮れています。

4

4 に答える 4

129

コンパイルとリンクはどのように行っていますか?次のように、両方のファイルを指定する必要があります。

gcc testpoint.c point.c

...両方の機能をリンクすることを認識できるようにします。ただし、現在記述されているコードでは、反対の問題が発生します。それは、の複数の定義ですmain。1つ(間違いなくpoint.cにあるもの)を削除する必要があります。

大規模なプログラムでは、通常、変更されていないものを再コンパイルしないように、別々にコンパイルしてリンクします。通常、makefileを介して実行する必要があることを指定し、を使用makeして作業を実行します。この場合、次のようなものになります。

OBJS=testpoint.o point.o

testpoint.exe: $(OBJS)
    gcc $(OJBS)

1つ目は、オブジェクトファイルの名前の単なるマクロです。で展開され$(OBJS)ます。2つ目は、makeに1)実行可能ファイルがオブジェクトファイルに依存していること、および2)オブジェクトファイルと比較して古い場合に実行可能ファイルを作成する方法を指示するルールです。

makeのほとんどのバージョン(MinGWのバージョンを含む)には、Cソースファイルからオブジェクトファイルを作成する方法を指示する「暗黙のルール」が組み込まれています。通常は次のようになります。

.c.o:
    $(CC) -c $(CFLAGS) $<

これは、Cコンパイラの名前がCCという名前のマクロ(暗黙的にのように定義されている)にあることを前提としており、(たとえば、最適化をオンにするために)CC=gccという名前のマクロで気になるフラグを指定できるようにします。ソースファイルの名前。CFLAGSCFLAGS=-O3$<

通常、これをという名前のファイルに保存しMakefile、プログラムをビルドするにmakeは、コマンドラインで入力するだけです。、という名前のファイルを暗黙的に検索し、Makefileそこに含まれるすべてのルールを実行します。

これの良い点はmake、ファイルのタイムスタンプを自動的に確認するため、最後にコンパイルしてから変更されたファイル(つまり、「。c」ファイルの方が新しいファイル)のみが再コンパイルされることです。一致する「.o」ファイルよりもタイムスタンプ)。

また、1)大規模なプロジェクトでは、makeの使用方法にさまざまなバリエーションがあり、2)makeの選択肢もたくさんあることに注意してください。ここでは、最低限のハイポイントしかヒットしていません。

于 2011-04-05T22:20:52.087 に答える
25

最近この問題が発生しました。私の場合、拡張子に応じて各ファイルで使用するコンパイラ(CまたはC ++)を選択するようにIDEを設定し、.cC ++コードから(つまりファイルから)C関数を呼び出そうとしていました。

.hC関数のファイルは、この種のガードでラップされていませんでした。

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

追加することもできましたが、変更したくなかったので、次のようにC++ファイルに含めました。

extern "C" {
#include "legacy_C_header.h"
}

(Extern "C"の効果についての彼の明確な説明については、UncaAlbyへのハットチップ。)

于 2017-10-26T20:58:50.323 に答える
9

問題は、testpoint.cをコンパイルしようとすると、point.hが含まれているのに、point.cがわからないことだと思います。point.cにはの定義があるためcreate、point.cがないと、コンパイルが失敗します。

私はMinGWに精通していませんが、point.cを探すようにコンパイラーに指示する必要があります。たとえば、gccを使用すると、次のようになります。

gcc point.c testpoint.c

他のが指摘しているように、あなたはあなたのmain関数の1つを削除する必要があります。あなたは1つしか持つことができないからです。

于 2011-04-05T22:22:21.043 に答える
4

「extern」キーワードをpoint.hの関数定義に追加します

于 2011-04-05T22:25:09.883 に答える