Reputation: 4885
If I use C code in a c++ environment and I include all of the code inside the header, everything works fine. If I try to declare C functions in a header and them implement them in a .c or .cpp file, I get the following error:
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 or .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;
}
Upvotes: 3
Views: 303
Reputation: 40614
There's actually two things wrong here:
If you declare a function inline, it won't be compiled unless needed in the given compilation unit. So the Vec2.o file won't contain it, and the linker won't be able to find it. Inline functions always have to be put into headers, so their implementation is seen by the compiler in every compilation unit it is needed in.
As H2CO3 said, C++ uses name mangling: it encodes the parameter types into the function name to allow for overloading. C doesn't do this. So, if you compile a c++ file that uses your function, it will want to link against some weird name, not just against "vec2_norm". To be able to link C code into C++ code, you have to tell the compiler that it should use the C symbol names.
Most often, people do that by writing headers of this form:
#ifdef __cplusplus
extern "C" {
#endif
Vec2 vec2_norm(Vec2 v);
#ifdef __cplusplus
}
#endif
By the way, does anybody know how to correctly format preprocessor directives in stackoverflow?
Upvotes: 0
Reputation: 24812
though I tested your code sample, and it compiled fine for me using g++/gcc and clang++/clang, when you want to compile C based source code, it's always a good idea to add extern "C" {}
around it so the compiler does not do C++ name mangling on those functions:
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
float x;
float y;
} Vec2;
inline Vec2 vec2_norm(Vec2 v);
#ifdef __cplusplus
};
#endif
and
extern "C" {
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;
}
};
btw, about the inline
you're using in your code, even though it is not mandatory to have an inline function defined only in the header, it's strongly advised to do it, so you don't have to copy the inline body to every translation unit where you'll include that header, because of the one definition rule.
As wikipedia says on the topic:
Some things, like types, templates, and extern inline functions, can be defined in more than one translation unit. For a given entity, each definition must be the same. Non-extern objects and functions in different translation units are different entities, even if their names and types are the same.
But in the end, whether it is a good or a bad idea depends on your design choices.
HTH
Upvotes: 4