54

私は C の初心者で、Code::Blocks を使用してコンソール アプリケーションを作成しようとしていました。(簡略化された) コードは次のとおりです: main.c:

#include <stdio.h>
#include <stdlib.h>
#include "test.c" // include not necessary for error in Code::Blocks

int main()
{
    //t = test(); // calling of method also not necessary
    return 0;
}

test.c:

void test() {}

このプログラムをビルドしようとすると、次のエラーが発生します。

*path*\test.c|1|`_ test' の複数の定義|
obj\Debug\main.o:*path*\test.c|1|ここで最初に定義|

テストを複数定義する方法はありません (ただし、アンダースコアがどこから来ているのかはわかりません)。定義が何らかの形で 2 回含まれている可能性は非常に低いようです。これがすべてのコードです。

このエラーは、test または test.c と呼ばれる他の関数またはファイルとの名前の競合によるものではないことを除外しました。複数の定義と最初の定義は、同じファイルの同じ行にあることに注意してください。

これを引き起こしている原因と、それに対して何ができるかを誰かが知っていますか? ありがとう!

4

8 に答える 8

106

test.c実際に2 回のソース コードをコンパイルします。

  • 初めてtest.c自分自身をコンパイルするとき、
  • main.cすべてのtest.cソースを含むコンパイル時の 2 回目。

main.c関数を使用するために必要なのtest()は、その定義ではなく単純な宣言です。これは、次のtest.hようなものを含むヘッダー ファイルを含めることによって実現されます。

void test(void);

これにより、入力パラメーターと戻り値の型を持つそのような関数が存在することがコンパイラーに通知されます。この関数が行うこと ( と 内{のすべて}) は、ファイルに残されますtest.c

main.c で、 に置き換え#include "test.c"ます#include "test.h"

最後のポイント: プログラムがより複雑になると、ヘッダー ファイルが複数回インクルードされる状況に直面することになります。これを防ぐために、ヘッダー ソースは次のような特定のマクロ定義で囲まれることがあります。

#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED

void test(void);

#endif
于 2009-03-23T10:00:19.743 に答える
27

アンダースコアはコンパイラによってそこに置かれ、リンカによって使用されます。基本的なパスは次のとおりです。

main.c
test.h ---> [compiler] ---> main.o --+
                                     |
test.c ---> [compiler] ---> test.o --+--> [linker] ---> main.exe

したがって、メイン プログラムには、関数プロトタイプなどの宣言のみで構成されるテスト モジュールのヘッダー ファイルを含める必要があります。

void test(void);

これにより、コンパイラは main.c がコンパイルされているときにそれが存在することを認識できますが、実際のコードは test.c、次に test.o にあります。

2 つのモジュールを結合するのはリンク フェーズです。

test.c を main.c にインクルードすることで、main.o で test() 関数を定義していることになります。次に、関数 test() を含む main.o と test.o をリンクしていると思われます。

于 2009-03-23T09:55:19.087 に答える
11

.c ファイルに他のソース ファイル (*.c) を含めないでくださいテスト関数の DECLARATION を含むヘッダー (.h) ファイルが必要で、別の .c ファイルに DEFINITION が必要だと思います。

このエラーは、テスト関数の複数の定義 (test.c に 1 つ、main.c にもう 1 つ) が原因で発生します。

于 2009-03-23T09:48:52.127 に答える
6

同様の問題があり、次の方法で解決しました。

次のように解きます。

関数プロトタイプ宣言とグローバル変数は test.h ファイルにある必要があり、ヘッダー ファイルでグローバル変数を初期化することはできません。

test.c ファイルでの関数定義とグローバル変数の使用

ヘッダーでグローバル変数を初期化すると、次のエラーが発生します

`_ test' の多重定義 | obj\Debug\main.o:パス\test.c|1|最初にここで定義|

ヘッダー ファイルでグローバル変数を宣言するだけで、初期化は機能しません。

それが役に立てば幸い

乾杯

于 2012-09-25T10:20:40.523 に答える
4

Code::Blocks プロジェクトに test.c を追加した場合、定義は 2 回表示されます。1 回は #include を介して、もう 1 回はリンカによって表示されます。必要がある:

  • #include "test.c" を削除します
  • 次の宣言を含むファイル test.h を作成します
  • ファイル test.h を main.c に含めます

于 2009-03-23T09:52:48.670 に答える
4

実装ファイル ( test.c) をインクルードすると、それが main.c の先頭に追加され、そこでコンパイルされてから、再び個別にコンパイルされます。したがって、関数testには 2 つの定義があります。1 つは のオブジェクト コードにmain.cあり、もう 1 つは のオブジェクト コードにありtest.c、ODR 違反が発生します。の宣言を含むヘッダー ファイルを作成し、testそれを に含める必要がありmain.cます。

/* test.h */
#ifndef TEST_H
#define TEST_H
void test(); /* declaration */
#endif /* TEST_H */
于 2009-03-23T09:51:33.213 に答える
4

Visual Studio を使用している場合は、ヘッダー ファイルの先頭で「#pragma once」を実行して、「#ifndef ...」ラッピングと同じことを行うこともできます。他のいくつかのコンパイラもおそらくそれをサポートしています.. .. ただし、これを行わないでください :D #ifndef-wrapping を使用して、コンパイラ間の互換性を実現してください。#pragma once も実行できることをお知らせしたかっただけです。他の人のコードを読むときに、このステートメントにかなり遭遇する可能性があるからです。

頑張ってください

于 2009-03-23T10:16:14.853 に答える