[C++] 函数指针的学习与运用
什么是函数指针
函数指针:如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。
函数指针变量定义形式
函数返回值类型 (*函数指针变量名) (函数参数列表);
如何用函数指针调用函数
int max(int x, int y); /*声明一个函数*/ int (*pMax) (int x, int y); /*定义一个函数指针*/ pMax = max; /*将max函数的首地址赋给指针变量p*/
使用实例
#include <iostream>
using namespace std;
int max(int x, int y);
int main(int argc, char const *argv[])
{
    int (*pMax)(int, int);
    pMax = max;
    int max_val = pMax(10, 100);
    cout << max_val << endl;
    return 0;
}
int max(int x, int y)
{
    return x>y ? x : y;
}
为某一函数型定义其函数指针类型
定义语句
typedef (*函数指针类型名)(函数参数列表); /*e.g*/ typedef int(*max_func_type)(int, int);
这个就可以用像定义普通变量一样,定义一个函数指针变量了,前面的例子可以改成如下:
#include <iostream>
using namespace std;
int max(int x, int y);
typedef int(*max_func_type)(int, int);
int main(int argc, char const *argv[])
{
    max_func_type pMax = max;  /*这就很符合平常定义变量的语法*/
    int max_val = pMax(10, 100);
    cout << max_val << endl;
    return 0;
}
int max(int x, int y)
{
    return x>y ? x : y;
}
函数指针的高级使用
开发过程中,需要用到某个dll库文件时,但只有说明文档,而开发用的lib文件和头文件都丢失了,这种情况下怎么办?方法就是:
- 使用HMODULE hModule = LoadLibrary(LPCTSTR lpFileName)加载这个dll文件,
- 再用GetProcAddress(hModule, "函数名")获取需要调用的函数的内存地址(函数指针)。
还是前面的例子,把max()函数封装到一个dll里,代码如下:
/*CMakeLists.txt*/
cmake_minimum_required(VERSION 3.0)
project(max)
FILE(GLOB SC "*.cpp" "*.h")
add_library(${PROJECT_NAME} SHARED ${SC})
/*max.h*/ #ifndef __MAX_H__ #define __MAX_H__ extern "C" __declspec(dllexport) int __cdecl max(int x, int y); /*注意这里*/ #endif // !__MAX_H__
上面需要注意的那一行,为了让max函数在dll文件的导出表里的名称就是“max”,其实我有点偷懒了,正确的声明应该是把__cdecl 换成 __stdcall,这样才符合GetProcAddress()返回的函数指针对应的函数调用规范,但用了__stdcall后,dll中的导出函数名就不是简单的“max”了。至于函数调用规范的内容,就可能开另外一个单章进行总结了。有兴趣的可以网上搜,自个进行了解。
/*max.cpp*/
#include "max.h"
int __cdecl max(int x, int y)
{
	return x > y ? x : y;
}
在另外一个项目中使用上面封装的dll,注意只要dll文件,lib文件与头件别也复制过来了:
/*CMakeLists.txt*/
cmake_minimum_required(VERSION 3.0)
project(LoadDll)
FILE(GLOB SC "*.cpp" "*.h")
add_executable(${PROJECT_NAME} ${SC})
/*main.cpp*/
#include <Windows.h>
#include <iostream>
using namespace std;
typedef int(*max_func_type)(int, int);
int main(int argc, char** argv)
{
	HMODULE hDll = LoadLibrary("max.dll"); /*加载dll文件*/
	if (!hDll)
	{
		cerr << "Load max.dll error" << endl;
	}
	max_func_type pMax = (max_func_type)GetProcAddress(hDll, "max");  /*获取函数地址,赋值函数指针变量pMax*/
	if (!pMax)
	{
		cerr << "function max not found" << endl;
	}
	else 
	{
		int ret = pMax(100, 10);  /*通过函数指针调用max函数*/
		cout << "result: " << ret << endl;
	}
	FreeLibrary(hDll);
	return 0;
}
PS:其实还有一个进阶的用法, 就是已经有一段编译好,且可独立运行的代码(目标代码),先加载到内存,把对应的内存地址赋值给一个函数指针,方便后面的调用,但这里涉及到一个内存权限问题,一般这样的加载只有可读写权限,但调用是需要执行权限的,这就需要调用系统API对这段内存进行赋权!!
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号