C ++中的标头中的C
Posted
技术标签:
【中文标题】C ++中的标头中的C【英文标题】:C out of header in C++ 【发布时间】:2013-06-22 19:57:19 【问题描述】:如果我在 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;
【问题讨论】:
Name mangling... Linker error calling C-Function from Objective-C++的可能重复 我刚刚测试过,它在我使用 g++ 以及当我使用 clang 时编译得很好 如果删除“内联”子句,错误是否仍然存在? 【参考方案1】:虽然我测试了您的代码示例,并且它使用 g++/gcc 和 clang++/clang 对我来说编译得很好,但是当您想要编译基于 C 的源代码时,在它周围添加 extern "C"
总是一个好主意,这样编译器不对这些函数进行 C++ 名称修改:
#ifdef __cplusplus
extern "C"
#endif
typedef struct
float x;
float y;
Vec2;
inline Vec2 vec2_norm(Vec2 v);
#ifdef __cplusplus
;
#endif
和
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;
;
顺便说一句,关于您在代码中使用的inline
,即使强制 仅在标头中定义内联函数,强烈建议这样做,所以由于一个定义规则,您不必将内联正文复制到将包含该标题的每个翻译单元。
正如***在topic 上所说:
有些东西,比如类型、模板和外部内联函数,可以在多个翻译单元中定义。对于给定的实体,每个定义必须相同。不同翻译单元中的非外部对象和函数是不同的实体,即使它们的名称和类型相同。
但最终,好主意还是坏主意取决于您的设计选择。
HTH
【讨论】:
实现在.cpp
文件中,对吗?所以不需要在那里测试__cplusplus
。此外,正确的测试是#if __cplusplus
。一些 C/C++ 编译器在 C 语言模式下运行时会#define __cplusplus 0
。
虽然我认为 C++ 文件保留#if define __cplusplus
并没有什么坏处,你说得对,但我没有想到可能仍然是真的第二种情况(虽然我不知道哪些编译器会这样做)。
有趣的事情:刚刚得到一个编辑添加#ifdef __cplusplus
:-)
标头应使用#if __cplusplus
。实现文件只需要无条件extern "C"
。
“所以编译器不会对这些函数进行名称修改” - 相反,编译器会对这些函数使用 C 修改。【参考方案2】:
这里实际上有两个问题:
如果你声明了一个内联函数,除非在给定的编译单元中需要,否则它不会被编译。所以 Vec2.o 文件将不包含它,并且链接器将无法找到它。内联函数总是必须放在头文件中,因此编译器在每个需要它的编译单元中都可以看到它们的实现。
正如 H2CO3 所说,C++ 使用名称修饰:它将参数类型编码为函数名称以允许重载。 C 不这样做。所以,如果你编译一个使用你的函数的 c++ 文件,它会想要链接一些奇怪的名字,而不仅仅是“vec2_norm”。为了能够将 C 代码链接到 C++ 代码,您必须告诉编译器它应该使用 C 符号名称。
大多数情况下,人们通过编写这种形式的标题来做到这一点:
#ifdef __cplusplus
extern "C"
#endif
Vec2 vec2_norm(Vec2 v);
#ifdef __cplusplus
#endif
顺便问一下,有人知道如何正确格式化***中的预处理器指令吗?
【讨论】:
关于你的问题,这不是#
的错,而是因为当你在列表之后执行代码块时它会出错。只需在代码块前添加一些文本,就不会乱了。参考我的编辑。以上是关于C ++中的标头中的C的主要内容,如果未能解决你的问题,请参考以下文章