为什么在extern“ C”中定义__cplusplus

时间:2019-07-10 09:55:10

标签: c++ c mpi

在外部"C" { }中仍定义了宏__cplusplus。当我想在动态加载的库头中包含mpi.h的C版本时,这将无法工作,因为mpi.h仍会找到__cplusplus并仍会像由...打开一样加载C ++。

#undef __cplusplus与gcc一起使用。但是我不想依靠这个。

那么如何编写一个C ++程序  -使用cpi版本的mpi和  -链接到使用mpi C版本的C库(其中#include <mpi.h>已经出现在标题中了?

示例代码:

library.h:

#ifdef __cplusplus
extern "C" {
#endif

#include <mpi.h>

void library_do(MPI_Comm comm);

#ifdef __cplusplus
}
#endif

program.cpp:

#include <library.h>

#include <mpi.h>

int main() {
  MPI::Init();
  // do some mpi C++ calls...  
  library_do(MPI::COMM_WORLD);
  MPI::Finalize();
}

如果有人想在此处播放示例库。c:

#include <stdio.h>
#include "library.h"

void library_do(MPI_Comm comm)
{
    int rank;
    MPI_Comm_rank(comm, &rank);
    printf("MPI Rank: %d", rank);
}

并编译我尝试的所有内容

mpicc -shared library.c -o lib.so
mpicxx program.cpp -l lib.so

6 个答案:

答案 0 :(得分:6)

如果编译器是C ++编译器,则

__cplusplus将始终由编译器定义。 extern "C" {}只为您提供C链接,因此其中的代码可与C编译器很好地配合。

答案 1 :(得分:3)

因为它们是不同的东西。 extern "C" {}告诉编译器如何导出符号(see here),而__cplusplus告诉您可以使用C ++代码,以便您的库可以在#ifdef之间使用不同的代码路径。

答案 2 :(得分:3)

使用重点

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

是为了防止C ++修改名称。基本上,我们说的是不要像传统的C ++函数调用那样使用名称修饰,而是不要修饰它。 此链接可能很有用Name mangling

它用于使C头与C ++兼容。 标志__cplusplus是在C ++编译器中自动定义的。

答案 3 :(得分:2)

当然是定义好的。仍然是在extern "C"块内编译代码的C ++编译器。它不会停止将代码视为C ++,仅确保使用C调用/命名约定。

如果标头不能由C ++编译器编译,则唯一的办法是创建一个公开C ++兼容API的 C 包装器。

答案 4 :(得分:2)

编译器输出以下内容:

In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:61:0,
                 from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
                 from /usr/include/c++/4.8.2/map:60,
                 from /usr/include/openmpi-x86_64/openmpi/ompi/mpi/cxx/mpicxx.h:38,
                 from /usr/include/openmpi-x86_64/mpi.h:2674,
                 from x1.cpp:6:
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:72:3: error: template with C linkage
   template<typename _Iterator, typename _Container>
   ^
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:85:3: error: template with C linkage
   template<bool>
   ^
...

mpi.h标头检测到它正在被编译为C ++,因此包含C ++特定的功能。但是,模板(除其他外)不适用于C链接(例如,标头在extern "C"块内)。

移动包含在extern "C"上方的包含内容:

#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

void library_do(MPI_Comm comm);

#ifdef __cplusplus
}
#endif

答案 5 :(得分:1)

如果您使用C ++程序#include <mpi.h>,请不要在其中使用extern "C"。至少OpenMPI和Intel MPI在标头本身中为您执行此操作-如果定义了__cplusplus

您可能会遇到麻烦,因为某些MPI实现仍在mpi.h中定义了已从标准中删除的C ++接口。这显然在extern "C"下失效。例如,对于OpenMP,您可以通过设置OMPI_SKIP_MPICXX来跳过。这样,双extern "C"就可以了,但是我还是不推荐。

更新:如果您无法修改库头,请在#include <mpi.h>之前#include <lib.h>

也就是说,您不应将C ++绑定用于MPI。三年后,将它们从标准中删除