百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

白话函数指针(白话函数指针怎么表示)

citgpt 2024-07-10 14:44 10 浏览 0 评论

什么是函数?

从本质意义上讲,函数就是用来完成一定功能的。针对于编译型语言来说,编译器会将函数编译成一段具有特定功能的可执行代码块。函数的定义包含三个重要部分(返回类型、参数类型、调用约定)。

什么是指针?

一种特殊的变量,用来保存地址值,某类型的指针指向某类型的地址。

白话函数指针(白话函数指针怎么表示)

何为函数指针?

就是一种特殊的指针——指向一个函数的指针,其保存的值就是函数的地址。

函数是如何被调用的?

在(机器码)汇编语言层面,调用一个函数(过程), 通过call指令完成,通常用call+函数地址完成函数调用,因此,针对于底层的机器码,只需要知道一个函数的地址和传参模式,即可完成函数调用。

函数指针如何定义?

任何变量定义都包含三部分: 变量类型 + 变量名 = 初值,那么定义一个函数指针,首先我们需要知道要定义函数指针(指针类型)。

int __stdcall AddImplement(int a, int b) 
{ return a + b;
}

这个函数的类型是有两个整型参数,函数调用约定为__stdcall,返回值是个整型, 对应的函数指针类型为:

int(__stdcall *)(int a, int b)

定义类型时候,参数名是也可去掉的(只需要关系函数的本质定义:返回类型、参数类型、调用约定)

int(__stdcall *)(int, int)

并且可以用typedef将其命令:

typedef int(__stdcall *fnAdd)(int a, int b);

这个时候fnAdd就等价于:

int(__stdcall *)(int, int)

注意:在作为一个长期接触函数指针或者动态调用的开发人员,必须要注意什么函数指针类型时候,是否和真实需要调用的函数调用约定保持一致,如果不一致,会导致汇编代码传递参数的方式不正确,直接造成栈溢出。


接下来,咱们通过三个例子来深入理解函数指针。

1. 加法函数实例

我们从VS调试工具和输出中同时都得到fAdd的值是0x00CE1210,在内存中得到0x00CE1210地址开始的值分别是

0x55 0x8b 0xec 0x8b 0x45 0x08 0x03 0x45 0x0c 0x5d 0xc3 0xcc

我们再用VS反编译工具得到AddImplement函数的反编译代码,其效果如下图:

可以得到函数AddImplement的其实地址是0x00CE1210,同时,可以可以得到的其机器码:

0x55 0x8b 0xec 0x8b 0x45 0x08 0x03 0x45 0x0c 0x5d 0xc3 0xcc

从这个例子我们得出函数指针的本质:指向一个函数的指针,其保存的值就是函数的地址。

2. 调用C++私有函数实例

笔者觉得这个例子才是真正展现函数指针精华的例子,学习过C++或者Java的同学都知道,类声明的private函数或者变量,在类外部不能直接访问(排除friend的情况)。如果直接调用,由于开发语言的约定,直接在编译过程就会警报语法错误。那么,怎么达到这种效果呢,嘿嘿,使用函数指针吧,且看如下例子:

笔者建议童鞋们在实际工作中不要使用该方法进行代码编写和接口调用。

3. GetProcAddress实例

学习过C/C++系统编程(Windows或者Linux)的童鞋都知道,所谓的API编程,其实是基于系统接口或者第三方接口进行开发,通常这些接口都是没有源码,通过Windows上的DLL或者Uni*上的so提供函数功能。

下面例子讲述通过动态调用Windows的Kernerl32.DLL中的GetComputerNameW函数获取当前机器名的例子。

不过有童鞋有疑问,难道每次动态调用其它模块的接口都要这么操作或者函数指针吗?当然不是,一般开发过程中,一般开发都是直接引入第三方动态开发库,编译出来的二进制文件(PE文件或者ELF文件)的导入表中,系统的PE装载器会帮我们完成上述操作。


最后给大家展示一下,我们的劳动成果。

目前,圈内有很多公司的大牛加入,与我们一起帮助在这条路上成长的小伙伴,这条路任重而道远,但我们依然坚持着,期待你的加入...

如果觉得内容不错,记得关注和分享哦,分享是一件有意义的事情!!!

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: