4. extern "C"用法详解

1.extern关键字

extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其他模块中使用。与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块使用

实例:

1)变量的调用

在extern1.cpp中定义一个全局变量:

int a = 12;

在externMain.cpp中:

#include <iostream>
using namespace std;

int a;

int main()
{
	cout << a << endl;

	system("pause");
	return 0;
}

这样编译就会出现错误:

这时需要在externMain.cpp中,在int a前面添加关键字extern

extern int a;

这时便能成功打印出来变量a的值了,注意变量前面的类型不能省略,否则编译器报错:缺少类型说明符

如果我们在extern1.cpp中,在int a前面添加static修饰符,再编译会报错:

说明static修饰的变量不能在其他文件中使用

2)函数的调用

在extern1.cpp中,定义一个函数:

#include <iostream>
using namespace std;

void fun()
{
	cout << "helloworld" << endl;
}

在externMain.cpp中调用该函数:

#include <iostream>
using namespace std;

int main()
{
	fun();

	system("pause");
	return 0;
}

如果这样直接编译的话,会报错:

需要在函数使用前进行声明:

#include <iostream>
using namespace std;

void fun();

int main()
{
	fun();

	system("pause");
	return 0;
}

如果我们在函数声明的地方加上extern关键字,程序也是可以运行的:

extern void fun();

对于外部函数,extern可以省略,但对于外部变量,extern就不能被省略

2. extern "C"关键字

extern "C"指示编译器这部分代码按C语言方式编译和链接进行编译,而不是C++的方式

3.C函数与C++函数编译的区别

C++是面向对象的语言,支持函数重载,而C不支持。函数被C++编译后在符号库中的名字和C语言中的不同。例如,某函数原型为:

void foo(int x, int y);

该函数被C编译器编译后在符号库中名字为foo或_fun@4,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能产生的名字不同,这样的名字包含了函数名、函数参数数量及类型信息,而不再是函数原来的名字了),C++就是靠这种机制实现函数重载的

实例:

1)之前DLL项目产生的.dll文件,在Dependency中打开查看:

因为之前在函数导出时,我们在前面添加了extern “C”,所以现在我们发现,函数的名字跟我们定义的函数名字一样

现在我们在DLL项目去去掉extern “C”:

#include "func.h"
#include "stdafx.h"

_declspec(dllexport) int SquareSum(int a, int b)
{
	return (a*a + b * b);
}

_declspec(dllexport) int SumSquare(int a, int b)
{
	return ((a + b)*(a+b));
}

重新生成后在Dependency中打开查看:

我们发现,函数名称已经改变,与我们定义的函数名字不一样了

此时如果我们继续在.exe文件中调用该.dll文件便会找不到该函数地址,程序不会执行

如果我们使用Dependency中的函数名,发现程序又会正常运行了


#include <iostream>
#include <windows.h>
using namespace std;
//#include "func.h"
//不需要.h头文件和.lib文件
//#pragma comment(lib,"DynamicLib64.lib")

int main()
{
	int a = 34;
	int b = 32;

	//加载DLL文件
	HMODULE h = LoadLibrary("DynamicLib32.dll");
	//定义一个函数指针类型
	typedef int(*PFUNC)(int, int);
	//通过函数名称来获取函数地址
	PFUNC pSquareSum = (PFUNC)GetProcAddress(h, "?SquareSum@@YAHHH@Z");
	PFUNC pSumSquare = (PFUNC)GetProcAddress(h, "?SumSquare@@YAHHH@Z");
	//通过函数序号来获取函数地址
	//PFUNC pSquareSum = (PFUNC)GetProcAddress(h, (char*)1);
	//PFUNC pSumSquare = (PFUNC)GetProcAddress(h, (char*)2);
	//调用函数
	cout << pSquareSum(a, b) << endl;
	cout << pSumSquare(a, b) << endl;
	//释放DLL文件
	FreeLibrary(h);

	system("pause");
	return 0;
}

执行结果:

从该例子中我们也可以简单的总结出:extern “C”的作用就是让函数在编译时按照C语言的方式编译,保证函数名称不改变

4. extern “C”的使用场景

1)在C++环境下使用C语言方式编译DLL,保证函数名称不改变:

extern "C" _declspec(dllexport) int SquareSum(int a, int b)
{
	return (a*a + b * b);
}

extern "C"  _declspec(dllexport) int SumSquare(int a, int b)
{
	return ((a + b)*(a+b));
}

2)在C++中引用C语言中的函数和变量时,需要在包含C语言函数和变量的头文件的位置进行下列处理:

extern "C"
{
#include "extern1.h"
}

实例:

在extern1.c中:

#include "stdio.h"

int a = 12;

void fun()
{
	printf("helloworld\n");
}

在externMain.cpp中:

#include <iostream>
using namespace std;

extern int a;
void fun();

int main()
{
	cout << a << endl;

	fun();

	system("pause");
	return 0;
}

 编译错误:

修改方法:在每个变量和函数声明前面添加extern “C”

#include <iostream>
using namespace std;

extern "C" int a;
extern "C" void fun();

int main()
{
	cout << a << endl;

	fun();

	system("pause");
	return 0;
}

执行结果:

如果extern1.c中变量和函数太多,我们每次都这样添加extern “C”很不方便,所以我们可以在包含extern1.cpp中函数和变量的头文件上加extern “C”

extern1.h文件中:

#pragma once

extern int a;

void fun();

externMain.cpp中:

#include <iostream>
using namespace std;

extern "C"
{
#include "extern1.h"
}

int main()
{
	cout << a << endl;

	fun();

	system("pause");
	return 0;
}

这样也会执行成功:

注意:

extern “C”不允许在C语言中使用,否则编译错误

为了在C语言和C++语言中都能正常使用,我们可以使用标准写法,利用宏定义:

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

#include "extern1.h"

#ifdef __cplusplus
}
#endif // __cplusplus

这样就能在C语言中不调用extern “C”{ },而在C++中调用extern “C”{ },是代码具有了通用性

5.注意事项

1)在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern “C”声明,在.c文件中包含extern “C”时会出现编译语法错误

2)把extern “C”放在class的前面,编译器还是会忽略掉,最后产生的还是C++修饰符,而不是C修饰符

猜你喜欢

转载自blog.csdn.net/qq_33757398/article/details/81566104
今日推荐