web-dev-qa-db-ja.com

Cエラー:関数への未定義の参照ですが、ISが定義されています

単純なプログラムですが、このコンパイラエラーが発生し続けます。コンパイラに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;
}

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

52
upswimsdn

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

gcc testpoint.c point.c

...そのため、両方の機能を一緒にリンクすることがわかります。ただし、今作成したコードでは、反対の問題に遭遇します。mainの複数の定義です。 1つ(間違いなくpoint.cの1つ)を削除する必要があります。

大規模なプログラムでは、通常、個別にコンパイルおよびリンクして、変更されていないものを再コンパイルしないようにします。通常、メイクファイルを介して実行する必要があるものを指定し、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のように暗黙的に定義される)にあると想定し、CFLAGSという名前のマクロで気にするフラグを指定できるようにします(たとえば、CFLAGS=-O3最適化を有効にする)および$<は、ソースファイルの名前に展開される特別なマクロです。

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

これの良い点は、makeがファイルのタイムスタンプを自動的に調べるため、最後にコンパイルしてから変更されたファイル(つまり、「。c」ファイルには、対応する「.o」ファイルよりも新しいタイムスタンプがあります)。

また、1)大規模プロジェクトの場合はmakeの使用方法に多くのバリエーションがあり、2)作成する代替品もたくさんあることに注意してください。ここでは、最低限の高得点にしかヒットしていません。

83
Jerry Coffin

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

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

#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"の効果 の明確な説明については、 ncaAlby に感謝します。)

9
cp.engr

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

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

gcc point.c testpoint.c

もちろん others が指摘しているように、main関数は1つしか持てないため、削除する必要があります。

6
Cam

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

1

最近、同様の問題に戸惑いました。次に、関数の前方宣言が「静的」であるため、内部リンケージがあり、見えないことに気付きました。定義にもかかわらず、キーワードはありませんでした。

宣言を確認してください!

0
Calmarius