一、C++调用C
实际工程中C++和C代码相互调用是不可避免的
1.C++编译器能够兼容C语言的编译方式 |
2.C++编译器会优先使用C++编译的方式 |
3.extern关键字能强制让C++编译器进行C方式的编译 |
语法:
extern "C"
{
//do C-style compilation here
}
Example:
C语言文件 add.c :
#include "add.h"
int add(int a, int b)
{
return a + b;
}
C++文件 main.h:
int add(int a, int b);
C++文件 main.cpp:
#include <stdio.h>
extern "C" //头文件中的代码为C代码,所以必须用C方式编译。
{
#include "add.h"
}
int add(int a, int b)
{
int c = add(1,2);
printf("c = %d\n",c);
return 0;
}
extern "C"在C++中有一个函数名,它有“C”链接(编译器不会mangle 这个函数名),这样client C代码就可以链接到你的函数使用一个“C”兼容的头文件,它只包含你的函数的声明。你的函数定义包含在一个二进制格式(由你的C++编译器编译),client C'链接器将会链接到使用'C'的名称。
由于C ++有函数名称的重载而C没有,因此C ++编译器不能只使用函数名作为链接的唯一id,因此它通过添加有关参数的信息来mangle 函数名。 AC编译器不需要破坏名称,因为您不能在C中重载函数名。当您声明函数在C ++中具有extern“C”链接时,C ++编译器不会将参数/参数类型信息添加到用于函数名的连接。
这样你就知道,你可以显式地指定每个单独的声明/定义的“C”链接,或者使用一个block来对声明/定义的序列进行分组,以获得一个特定的链接:
extern "C" void foo(int);
extern "C"
{
void g(char);
int i;
}
如果你比较 关心技术方面的问题,它们列在C++03标准的第7部分中,这里有一个简短的总结(强调extern “C”):
1.extern “C”是一个链接规范 |
2.每个编译器都需要提供“C”链接 |
3.链接规范只在名称空间范围内发生 |
4.只有函数名和带有外部链接的变量名具有语言链接 |
5.具有不同语言连接的两个函数类型是不同的类型,即使在其他情况下是相同的 |
6.链接规范nest,内部决定了最终的链接 |
7.对于类成员来说,外部的“C”是被忽略的 |
8.在大多数带有特定名称的函数中,可以有“C”链接(不管名称空间) |
9. 'static' inside 'extern "C"'“是有效的;一个被声明的实体有内部链接,因此没有语言链接 |
10.从C++到其他语言中定义的对象,以及从其他语言中定义的对象,都是由实现定义和依赖于语言的。只有当两种语言实现的对象布局策略足够相似时,才可以实现这样的链接 |
二、如何使C语言代码既能在C编译中通过,又能在C++编译中通过?
语法:
#ifdef __cplusplus
extern "C" {
#endif
// all of your legacy C code here
#ifdef __cplusplus
}
#endif
这样做的目的是让您可以使用C++代码使用C头文件,因为将定义宏“cplusplus”。但是您仍然可以在遗留C代码中使用它,在那里没有定义宏,所以它不会看到唯一的C++结构。
Test:
#include <stdio.h>
#ifndef __cplusplus //如果没有定义宏
extern "C" //保留extern "C"
{
#endif
#include "add.h"
#ifdef __cplusplus //如果定义了宏
} //保留括号 }
#endif
int add(int a, int b)
{
int c = add(1,2);
printf("c = %d\n",c);
return 0;
}
<全文完>
参考资料: