[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文件和头文件都丢失了,这种情况下怎么办?方法就是:

  1. 使用HMODULE hModule = LoadLibrary(LPCTSTR lpFileName)加载这个dll文件,
  2. 再用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对这段内存进行赋权!!

posted @ 2020-08-19 01:09  dilex  阅读(241)  评论(0编辑  收藏  举报