3

C++ 環境で C コードを使用し、すべてのコードをヘッダー内に含めると、すべて正常に動作します。ヘッダーで C 関数を宣言しようとして、それらを .c または .cpp ファイルに実装すると、次のエラーが発生します。

Undefined symbols for architecture x86_64:
  "vec2_norm(Vec2)", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Vec2.h

#ifndef Physics_Engine_Test_Vec2_h
#define Physics_Engine_Test_Vec2_h

typedef struct
{
    float x;
    float y;
} Vec2;

inline Vec2 vec2_norm(Vec2 v);

#endif

Vec2.c または .cpp

#include "Vec2.h"
#include <math.h>

inline Vec2 vec2_norm(Vec2 v) {
    float len = v.x*v.x + v.y*v.y;
    if (len) {
        len = 1 / sqrtf(len);
        v.x *= len;
        v.y *= len;
    }
    return v;
}
4

2 に答える 2

0

ここには、実際には次の 2 つの問題があります。

  1. 関数をインラインで宣言すると、指定されたコンパイル単位で必要でない限りコンパイルされません。そのため、Vec2.o ファイルには含まれず、リンカーはそれを見つけることができません。インライン関数は常にヘッダーに配置する必要があるため、それらの実装は、必要なすべてのコンパイル単位でコンパイラーによって認識されます。

  2. H2CO3 が言ったように、C++ は名前マングリングを使用します。オーバーロードを可能にするために、パラメーターの型を関数名にエンコードします。Cはこれをしません。そのため、関数を使用する C++ ファイルをコンパイルすると、「vec2_norm」に対してだけでなく、奇妙な名前に対してリンクする必要があります。C コードを C++ コードにリンクできるようにするには、コンパイラに C シンボル名を使用するように指示する必要があります。

ほとんどの場合、人々はこの形式のヘッダーを書くことによってそれを行います:

#ifdef __cplusplus
    extern "C" {
#endif

Vec2 vec2_norm(Vec2 v);

#ifdef __cplusplus
    }
#endif

ところで、stackoverflow でプリプロセッサ ディレクティブを正しくフォーマットする方法を知っている人はいますか?

于 2013-06-22T20:20:59.017 に答える