外部"C" ---何时*确切*使用?
extern "C"---when *exactly* to use?
如果您想将此问题标记为重复问题,请注意,我已经阅读了有关此主题的问题,但仍有一些不清楚的地方。我的印象是,在包含C头和链接C代码时使用了此构造(如果我错了,请纠正我)。这是否意味着我在不处理对象文件时永远不必使用"extern C"?如果我错了,为什么不能把旧的C代码编译成C++,因为它很可能是合法的C++代码?
我对此有点不确定,因为我发誓我在C++中使用旧的C源代码时遇到过这样的情况:链接器错误只能用"extern C"解决,而库头确实有
#ifdef __cplusplus
#extern "C"{
#endif
//......
#ifdef _cplusplus
}
#endif
他们周围。
编辑:很抱歉不清楚,但我想问的是,只有在包含C头并链接到预先存在的C对象文件时才需要"extern C",这是否属实?如果这是真的(似乎是从下面的评论中判断的),为什么库头周围有"extern C"子句,为什么不能将它们作为C++包含和编译?
C的名称篡改规则不同。C可以具有与C++不同的ABI。仅这些原因就要求您在C++代码中嵌入C代码时使用extern "C"
。即使编译器可以编译C和C++代码,它也可能对这两种语言使用不同的名称篡改规则或ABI。
此外,你所说的"[C代码]很可能……合法的C++代码"并不完全正确,因为随着时间的推移,C和C++的分歧越来越大。它们有很多相似之处,但也有很多不同之处。
库本身是一个C对象文件,因此为了使用它,应用程序必须使用C-ABI来调用库中的函数,并且在对函数进行原型化时,需要向编译器提供适当的提示。
extern void libraryFunc();
如果该库实际上被编译为C,这是它支持C和C++的唯一方法,那么您需要为C++编译器添加注释,该注释必须链接为C。
#ifdef __cplusplus // only true when compiling with a C++ compiler
extern "C" {
#endif
extern void libraryFunc();
#ifdef __cplusplus
}
#endif
对于C编译器,这读取
extern void libraryFunc();
对于C++编译器,这将读取
extern "C" {
extern void libraryFunc();
...
}
相当于
extern "C" void libraryFunc();
如果extern的复制让你感到困扰,可以考虑:
#if defined __cplusplus
# define C_EXTERN extern "C"
#else
# define C_EXTERN extern
#endif
EXTERN_C {
void foo();
}
编译器和链接器现在知道在尝试调用/链接该函数时使用C ABI。
请注意,C++ABI是C ABI(应用程序二进制接口)的超集,因此如果您想共享代码,C是LCD,需要成为您的通用接口。C完全不知道C++"名称篡改"等
这里基本上回答了这个问题:何时使用extern"C";简单地说?
但相关的一点是,在C++中编译时,函数的名称会被"篡改",以编码有关函数的某些信息(如参数类型)。由于C++总是以相同的方式破坏函数名,因此被破坏的名称调用和对象文件中的内容是一致的。
如果你用C编译一个名为"foo"的文件,而在你的C++文件中你有extern foo(int c);
,那么C++编译会把"foo"修改成不同的东西,例如foo__Ic
(我刚刚编好了,实际的修改看起来会不同)。
同时,在用C编译器编译的纯C代码中,目标代码定义了简单的foo
符号。
然而,当整个东西被链接时,C++代码有一个它试图解析的外部符号foo__Ic
,它与C对象文件中定义的符号foo
不匹配。
希望能有所帮助。
还有一个案例尚未提及。extern "C"
指定了C链接,但C并不是唯一的其他语言。C链接也被其他语言使用,这些语言过于晦涩,无法拥有自己广泛接受的链接。例如,Java也使用C链接。显然,您无法用C++编译Java代码,因此您确实需要C++端的extern "C"
。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- C++:TypeDef使用元组
- 使用std::multimap迭代器创建std::list
- 从不同线程使用int64的不同字节安全吗
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么在全局范围内使用"extern int a"似乎不行?
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用Google Mock来模拟gettimeofday()
- 如何使用默认参数等选择模板专业化
- 为什么使用 "this" 指针调用派生成员函数?
- 如何在 c++11 中使用正则表达式找到确切的子字符串?
- 使用OpenSSL和C 来验证JWT的确切基本64 URL解码规则和实现
- 有没有办法将数字作为字符串,并在不使用浮点数或双精度数的情况下将其四舍五入到确切的位数
- 期望使用确切的对象实例作为参数进行调用
- 在Apple llvm 4.1上使用libc++与libstc++时,c++11支持的确切区别是什么
- 外部"C" ---何时*确切*使用?
- 如何使用 DrawText 查找在 Windows 中呈现的文本的确切像素高度
- 如何在opencv中使用surf算法在源图像中找到模板图像的确切角
- 没有使用终端获得确切的输出形式