为什么 __cplusplus 在 extern "C" 中定义
Why is __cplusplus defined within extern "C"
在 extern "C" { }
中,宏 __cplusplus
仍然被定义。当我想在动态加载的库的 header 中包含 mpi.h
的 C 版本时,这将不起作用,因为 mpi.h
仍然会找到 __cplusplus
并且仍然会加载它是由 C++ 打开的。
#undef __cplusplus
适用于 gcc。但是我不想依赖这个。
那么如何编写一个 C++ 程序
- 使用 C++ 版本的 mpi 和
- 与使用 mpi 的 C-Version 的 C-library 链接(其中 #include <mpi.h>
已经出现在 header?
示例代码:
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();
}
万一有人想在这里玩这个例子 library.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
如果编译器是 C++ 编译器,__cplusplus
将始终由编译器定义。 extern "C" {}
只给你 C 链接,所以里面的代码在 C 编译器上运行得很好。
因为它们是不同的东西。 extern "C" {}
告诉编译器如何导出符号 (see here),而 __cplusplus
告诉您可以使用 C++ 代码,因此您的库可以在 #ifdef
之间使用不同的代码路径。
当然是定义了。它仍然是一个 C++ 编译器,它编译了 extern "C"
块中的代码。它不会停止将代码视为 C++,只是确保使用 C calling/naming 约定。
如果头文件不能被 C++ 编译器编译,唯一的办法是创建一个 C 包装器,公开一个 C++ 兼容的 API.
使用的要点
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
是为了防止 C++ 进行的名称重整。我们基本上是说不要像传统的 C++ 函数调用那样使用名称修饰,而是让它不加修饰。
这个 link 可能会有用 Name mangling
它用于使 C 头文件与 C++ 兼容。
标志 __cplusplus
在 C++ 编译器中自动定义。
如果您 #include <mpi.h>
来自 C++ 程序,请不要在其周围放置 extern "C"
。至少 OpenMPI 和 Intel MPI 会在 header 本身为你做这件事——如果定义了 __cplusplus
。
您可能会遇到麻烦,因为某些 MPI 实现仍在 mpi.h
中定义已从标准中删除的 C++ 接口。这显然违反了 extern "C"
。例如,对于 OpenMP,您可以通过设置 OMPI_SKIP_MPICXX
来跳过它。然后双 extern "C"
工作,但我仍然不推荐它。
更新:如果您无法修改库 header,只需 #include <mpi.h>
之前 #include <lib.h>
。
就是说,您不应该为 MPI 使用 C++ 绑定。他们在 6 年多前 从标准中删除,在标准使用了 3 年后...
编译器输出如下:
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 header 检测到它被编译为 C++,因此包含 C++ 特定功能。然而,模板(除其他事项外)不适用于 C 链接(即如果 header 在 extern "C"
块内)。
移动上面的包含 extern "C"
:
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
在 extern "C" { }
中,宏 __cplusplus
仍然被定义。当我想在动态加载的库的 header 中包含 mpi.h
的 C 版本时,这将不起作用,因为 mpi.h
仍然会找到 __cplusplus
并且仍然会加载它是由 C++ 打开的。
#undef __cplusplus
适用于 gcc。但是我不想依赖这个。
那么如何编写一个 C++ 程序
- 使用 C++ 版本的 mpi 和
- 与使用 mpi 的 C-Version 的 C-library 链接(其中 #include <mpi.h>
已经出现在 header?
示例代码:
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();
}
万一有人想在这里玩这个例子 library.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
__cplusplus
将始终由编译器定义。 extern "C" {}
只给你 C 链接,所以里面的代码在 C 编译器上运行得很好。
因为它们是不同的东西。 extern "C" {}
告诉编译器如何导出符号 (see here),而 __cplusplus
告诉您可以使用 C++ 代码,因此您的库可以在 #ifdef
之间使用不同的代码路径。
当然是定义了。它仍然是一个 C++ 编译器,它编译了 extern "C"
块中的代码。它不会停止将代码视为 C++,只是确保使用 C calling/naming 约定。
如果头文件不能被 C++ 编译器编译,唯一的办法是创建一个 C 包装器,公开一个 C++ 兼容的 API.
使用的要点
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
是为了防止 C++ 进行的名称重整。我们基本上是说不要像传统的 C++ 函数调用那样使用名称修饰,而是让它不加修饰。 这个 link 可能会有用 Name mangling
它用于使 C 头文件与 C++ 兼容。
标志 __cplusplus
在 C++ 编译器中自动定义。
如果您 #include <mpi.h>
来自 C++ 程序,请不要在其周围放置 extern "C"
。至少 OpenMPI 和 Intel MPI 会在 header 本身为你做这件事——如果定义了 __cplusplus
。
您可能会遇到麻烦,因为某些 MPI 实现仍在 mpi.h
中定义已从标准中删除的 C++ 接口。这显然违反了 extern "C"
。例如,对于 OpenMP,您可以通过设置 OMPI_SKIP_MPICXX
来跳过它。然后双 extern "C"
工作,但我仍然不推荐它。
更新:如果您无法修改库 header,只需 #include <mpi.h>
之前 #include <lib.h>
。
就是说,您不应该为 MPI 使用 C++ 绑定。他们在 6 年多前 从标准中删除,在标准使用了 3 年后...
编译器输出如下:
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 header 检测到它被编译为 C++,因此包含 C++ 特定功能。然而,模板(除其他事项外)不适用于 C 链接(即如果 header 在 extern "C"
块内)。
移动上面的包含 extern "C"
:
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif