这两者之间有什么区别吗:
//MyFile.cpp
#include "myheader.hpp" //works fine in Apple Clang13 as well as 14
//MyFile.cpp
extern "C"
{
extern "C++"
{
#include "myheader.hpp". //compilation error in Apple Clang13
}
}
在后一种情况下,我得到了由于命名空间引起的编译错误,而在前一种情况下我没有得到任何这样的错误。此外,这个问题只发生在Apple Clang13
中,而不是在Apple Clang14
中。myheader.hpp
还包括许多其他头文件,包括boost/dynamic_bitset.hpp
。
// In file boost/dynamic_bitset.hpp
:
:
operator<<(std::basic_ostream<Ch, Tr>& os,
const dynamic_bitset<Block, Alloc>& b)
{
using namespace std;
const ios_base::iostate ok = ios_base::goodbit;
//error - undeclared identifier ios_base in apple clang13, did you mean std::ios_base
//works fine in clang13 after changing it to std::ios_base::iostate
//works fine in apple clang14 with no change
:
:
:
}
我的实际要求是我有一个客户端代码,其中包括我在extern "C"
块中的头部。我不能改变客户端的代码。在我的头部中,我想使用C++
代码。所以,代码是这样的:
//public_header.h //client's header, //can't change
extern "C"{
myheader.hpp
}
//myheader.hpp // This I can change
#ifdef my_flag //only defined for c++ targets
extern "C++"{
#include "boost/dynamic_bitset.hpp" //c++ code
}
}
所以,基本上我想在extern "C"
块中链接C++
。有没有其他方法可以不使用extern“C++”块来实现这一点?我的目标是在extern“C”块中使用boost header(模板)。
注-Clang 13中提到的升压头可重现问题。
1条答案
按热度按时间fdbelqdn1#
基于注解,看起来像
Vivek Mangal
不明白为什么需要extern“C”。C与C++重要区别
在C中,你可以做函数重载。C没有这个特性。所以如果你有C库函数,它们的名字是公开的(带下划线前缀-不重要)
现在,由于C有函数重载,这意味着在同一个名字下可以有多个函数。由于第一个C++编译器生成C代码,结果代码必须为这些重载提供唯一的函数名。因此引入了名称处理。基本上,编译器为每个函数重载生成唯一的名称,其中包含有关函数参数或命名空间的信息。
名称篡改问题
现在,当你尝试在C代码中使用C代码时,编译器必须知道哪些函数被编译为“C”,哪些函数是C,因此在喜欢的过程中,它可以通过常规名称找到“C”函数,并通过它们的名称找到C函数。
这就是为什么
extern "C"
进来-它基本上变成了名称mangling。如果extern "C"
不用于C代码中的C函数,你会看到链接器无法找到名称被mangled的函数定义的链接问题(因为函数在常规名称下可用)。行为良好的C库
现在,希望自己的库在C++代码中可用的C库开发人员应该提供如下所示的头文件:
这样,当在C模式下编译头文件时,
extern "C" {
会被预处理器忽略。当在C模式下编译头文件时,所有函数都被extern "C" {
包围,编译器不会对这些头文件使用名称mangling。这样C开发人员就不必做任何特殊的事情来使用C-API。
看起来你在这个场景中。
C++代码中的常规C库
很多时候,C库的作者并没有想到C++,那么这样的库的用户有责任确保名称修改被禁用。在这种情况下,你只需要做这样的事情:
这里不需要
#ifdef __cplusplus
,因为这个头文件使用了C++特性,不能在C
中使用,所以没有必要尝试让它在C
模式下工作。摘要
基于此,您应该清楚,您根本不需要使用
extern "C++"
!