文章目录
extern作为C++的关键字,常用于在本模块使用其他模块定义的变量或者函数,但当两个模块一个是.c文件,一个是.cpp文件时,又该怎么调用呢?extern “C”。(extern "C"必须出现在.cpp的文件中,在.c文件不会识别extern “C”)
在 C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”?
C++ 语言支持函数重载, C 语言不支持函数重载。 C++ 提供了 C 连接交换指定符号 extern “C”
解决名字匹配问题。
首先,作为 extern 是 C/C++ 语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字 extern 声明。例如,如果模块 B 欲引用该模块 A 中定义的全局变量和函数时只需包含模块 A 的头文件即可。这样,模块 B 中调用模块 A 中的函数时,在编译阶段,模块 B 虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块 A 编译生成的目标代码中找到此函数
extern “C” 是连接申明 (linkage declaration), 被 extern “C” 修饰的变量和函数是按照 C 语言方式编译和连接的 , 来看看 C++ 中对类似 C 的函数是怎样编译的:
作为一种面向对象的语言, C++ 支持函数重载,而过程式语言 C 则不支持。函数被 C++ 编译后在符号库中的名字与 C 语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
该函数被 C 编译器编译后在符号库中的名字为 _foo ,而 C++ 编译器则会产生像 _foo_int_int 之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为 “mangled name” )。 _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息, C++ 就是靠这种机制来实现函数重载的。例如,在 C++ 中,函数 void foo( int x, int y ) 与 void foo( int x, float y ) 编译生成的符号是不相同的,后者为 _foo_int_float 。 同样地, C++ 中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以 “.” 来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
1、C++使用C函数
//t2.h
//注意这里不能加#include<stdio.h>,因为extern是C++的关键字
#pragma once
extern "C" {
int add(int, int);
int sub(int, int);
}
//t3.c
#include<stdio.h>
int add(int a , int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
//t1.cpp
#include<iostream>
#include "t3.h"
using namespace std;
int main()
{
int a = 41;
int b = 9;
cout << add(a, b) << endl;
cout << sub(a, b) << endl;
a = t;
cout <<a << endl;
}
这时,在t1.cpp中,就可以使用在.C文件中定义的函数了。
2、C使用C++函数
//t2.h
#ifdef __cplusplus //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
extern "C" {
int add(int, int);
int sub(int, int);
#endif
#ifdef __cplusplus
}
//t2.cpp
#include"t2.h"
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
#endif
//t3.c
#include<stdio.h>
#include "t2.h"
int main()
{
int a = 41;
int b = 9;
printf("%d\n", add(a, b));
printf("%d\n", sub(a, b));
return 0;
}