xcode Apple Clang中的extern“C++”问题

jexiocij  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(202)

这两者之间有什么区别吗:

//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中提到的升压头可重现问题。

fdbelqdn

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库开发人员应该提供如下所示的头文件:

#ifndef HEADER_GUARD
#define HEADER_GUARD
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

// C function declarations:
....

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // HEADER_GUARD

这样,当在C模式下编译头文件时,extern "C" {会被预处理器忽略。当在C模式下编译头文件时,所有函数都被extern "C" {包围,编译器不会对这些头文件使用名称mangling。
这样C
开发人员就不必做任何特殊的事情来使用C-API。
看起来你在这个场景中。

C++代码中的常规C库

很多时候,C库的作者并没有想到C++,那么这样的库的用户有责任确保名称修改被禁用。在这种情况下,你只需要做这样的事情:

#ifndef HEADER_GUARD
#define HEADER_GUARD

#include <vector>
extern "C" {
#include <some-C-library/header1.h>
#include <some-C-library/header2.h>
}

class FOO {
};

#endif // HEADER_GUARD

这里不需要#ifdef __cplusplus,因为这个头文件使用了C++特性,不能在C中使用,所以没有必要尝试让它在C模式下工作。

摘要

基于此,您应该清楚,您根本不需要使用extern "C++"

相关问题