我正在写一个C程序(myapp),它需要使用一个特定的api;这个api是用C++写的。我曾经使用过C和C++,但从来没有同时使用过这两种语言,所以我感到很困惑。
所以,api提供了以下目录,我把它放在了一个叫include的文件夹里,和我的makefile处于同一级别。
libmyapi.a
api/api.h
我的主源文件是srcmyapp.c, 它包含了api,使用了 #include "api/api.h"
.
我的make命令是(加上一些标志,我没有列出,因为我认为它们与这里无关)。
gcc -Linclude -lmyapi -Iinclude src/myapp.c -o lib/myapp.sp -lrt
我遇到的问题是api.h文件包含了对命名空间的引用等等。例如,有一点它有。
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
显然C编译器不知道这意味着什么。
所以,我以为我需要用C++编译器来编译,但后来有人说我不需要,我可以用 "extern 'C'"来 "包装 "代码,但我不太明白。 在网上看了一圈,我没有任何进一步的了解。
我需要用C++编译吗(即使用g++)?
我是否需要 "封装 "代码,那是什么意思?我是否只需要做
#ifdef __cplusplus
extern "C" {
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
}
#endif
还是我只需要把这几行字包起来
namespace MyAPI {
namespace API {
然后再调用它们对应的}}?
头文件会调用其他头文件,所以有可能我需要在相当多的地方这样做。
到目前为止,我试过的所有变化都出现了错误和警告,但我不知道是我的封装做错了,还是g++编译器标志设置错了,还是使用了错误的编译器,还是什么!如果我知道使用的方法,我至少可以开始调试。如果我知道该用什么方法,至少可以开始调试了。 谢谢你!我在写一个C语言程序(C++编译器)。
你可以写一个小的C++程序,为api创建一个C的绑定。
Gvien这个API。
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
你可以创建c_api.
#ifdef __cplusplus
extern "C" {
#endif
struct api_handle_t;
typedef struct api_handle_t* api_handle;
api_handle myapi_api_create();
void myapi_api_some_function_using_api(api_handle h);
void myapi_api_destroy(api_handle h);
#ifdef __cplusplus
}
#endif
和 c_api.cpp
#include "c_api.h"
#include <myapi/api/stuff.hpp>
struct api_handle_t
{
MyAPI::API::SimpleConnection c;
};
api_handle myapi_api_create()
{
return new api_handle_t;
}
void myapi_api_some_function_using_api(api_handle h)
{
//implement using h
}
void myapi_api_destroy(api_handle h)
{
delete h;
}
用C++编译器编译,并在C项目中包含c_api.h文件,并链接到你用C++编译器创建的库和原始库。
基本上,你的C++库需要导出一个纯C的API。也就是说,它必须提供一个完全依赖于的接口。typedef
, struct
, enum
,预处理器指令宏(也许还有一些我忘了说的东西,不过必须都是有效的C代码)。如果没有这样的接口,你就不能把C代码和C++库连接起来。
这个纯C API的头需要既可以用C语言编译器又可以用C++编译器编译,但是,当你把它编译成C++时,你必须告诉C++编译器这是一个C接口。这就是为什么你需要将整个API包裹在
extern "C" {
//C API
}
当编译为C++时。然而,这根本不是C代码,所以你必须隐藏掉这个 extern "C"
的C编译器。这是通过添加预处理程序指令
#ifdef __cplusplus1
extern "C" {
#endif
//C API
#ifdef __cplusplus1
}
#endif
如果你不能改变你的库头,你需要创建一个包装API,提供这个纯C的API,并通过调用到相应的C++代码。
如何从C语言中调用C++函数?
通过编写调用函数,其声明在C和C++的通用子集中有效。并通过在C++中声明与C语言关联的函数。
我遇到的问题是,api.h文件中包含了对命名空间的引用。
这种头不是用C和C++的通用子集编写的,因此不能从C中使用。
我需要用C++编译吗(即使用g++)?
如果你有用C++写的函数定义,那么你需要用C++编译器编译这些C++函数。如果你有调用这些C++函数的C函数,那么你需要用C编译器来编译这些C函数。
一个最小的例子。
// C++
#include <iostream>
extern "C" void function_in_cpp() {
std::cout << "Greetings from C++\n";
}
// C
void function_in_cpp(void);
void function_in_c(void) {
function_in_cpp();
}
你不能这样做 你可以在你的C++程序中使用C函数。 但是你不能使用C++的东西,当C++被发明出来的时候,它允许C函数的兼容和重用,所以它被写成C的超集,允许C++调用所有的C库函数。
但是,事实并非如此。 当C被发明时,还没有定义C++语言。
你能调用C++函数的唯一方法是把你的整个项目转换成C++项目......你需要用C++编译器编译你的C函数(如果是普通的C函数,则用C编译器),但要想调用C++函数,必须把它编译成C++。 你应该用:
extern "C" {
void my_glue_func(type1 param1, type2 param2, ...)
{
/* ... */
}
} /* extern "C" */
然后把整个程序链接成一个C++程序(调用c++链接器)
这是因为C不知道关于 功能重载, 类初始化, 实例构造函数调用,等等。所以,如果你能把C++函数的名字拆开,以便能从C语言中调用它们(你最好不要尝试这样做),它们很可能会在未初始化的情况下运行,所以你的程序可能(很可能)会崩溃。
如果你的 main()
函数恰好是一个C函数,那么就没有问题了。 C++在设计时就考虑到了这个事情,所以。main()
被宣布为 隐性 作为 extern "C"
. :)