zoukankan      html  css  js  c++  java
  • 深入理解C语言-函数指针

    函数指针在C++中有着重要的应用,函数的函数名其本质就是代表一个地址,这个地址叫做函数入口,得到这个地址就可以对这个函数进行各种操作。

    函数类型基础

    • 函数三要素: 名称、参数、返回值
    • C语言中的函数有自己特定的类型
    • C语言中通过typedef为函数类型重命名,类似于定义数组
    typedef type name[m];//定义数组类型
    typedef type name(parameter list)//定义函数类型
    
    typedef int f(int, int);
    typedef void p(int);
    

    函数指针

    函数指针用于指向一个函数
    函数名是执行函数体的入口地址

    1. 可通过函数类型定义函数指针: FuncType* pointer;
    2. 也可以直接定义:type (*pointer)(parameter list);
      pointer为函数指针变量名
      type为指向函数的返回值类型
      parameter list为指向函数的参数类型列表
    typedef int(FUNC)(int);
    
    int test(int i)
    {
        return i * i;
    }
    
    void f()
    {
        printf("Call f()...
    ");
    }
    
    int main()
    {
        FUNC* pt = test;
        
        void(*pf)() = &f;
        
        pf();
        (*pf)();
        
        printf("Function pointer call: %d
    ", pt(3));
    }
    

    函数指针做函数参数

    当函数指针做为函数的参数,传递给一个被调用函数,
    被调用函数就可以通过这个指针调用外部的函数,这就形成了回调
    其本质就是把函数入口地址和函数参数传递给调用函数,也即对函数类型做了限定

    int add(int a, int b);
    int libfun(int (*pDis)(int a, int b));
    
    int main(void)
    {
     int (*pfun)(int a, int b);
     pfun = add;
     libfun(pfun);
    
    }
    
    int add(int a, int b)
    {
     return a + b;
    
    }
    
    int libfun(int (*pDis)(int a, int b))
    {
        int a, b;
        a = 1;
        b = 2;
        add(1,3)
        printf("%d", pDis(a, b));
    }
    

    假如int libfun(int (*pDis)(int a, int b))是一个库中的函数,就只有使用回调了,通过函数指针参数将外部函数地址传入来实现调用
    函数 add 的代码作了修改,也不必改动库的代码,就可以正常实现调用便于程序的维护和升级

    函数指针正向调用

    1. 函数指针做函数参数,调用方式
      被调用函数和主调函数在同一文件中,这种方式在实际开发中并不会用到
    2. 函数指针做函数参数
      被调用函数和主调函数不在同一个文件中、模块中。
      难点:理解被调用函数是什么机制被调用起来的。框架
      框架提前设置了被调用函数的入口(框架提供了第三方模块入口地址的集成功能)
      框架具备调用第三方模块入口函数
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef int(*EncDataFunc)(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen);
    
    int MyEncDataFunc(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen)
    {
    	int rv = 0;
    	char *p = "222222222222";
    
    	strcpy(outData, p);
    	*outDataLen = strlen(p);
    	return rv;
    }
    
    int Send_Data(EncDataFunc encDataFunc, unsigned char *inData, int inDataLen, unsigned char *outData, int *outDatalen)
    {
    	int rv = 0;
    	if (encDataFunc != NULL)
    	{
    		rv = encDataFunc(inData, inDataLen, outData, outDatalen, NULL, 0);
    		if (rv != 0)
    		{
    			printf("func encDataFunc() err.
    ");
    			return rv;
    		}
    	}
    	return rv;
    }
    
    int main()
    {
    	int rv = 0;
    
    	EncDataFunc encDataFunc = NULL;
    	encDataFunc = MyEncDataFunc;
    
    	// 第一个调用
    	{
    		unsigned char inData[2048];
    		int inDataLen;
    		unsigned char outData[2048];
    		int outDatalen;
    		strcpy(inData, "1111");
    		inDataLen = strlen(inData);
    		rv = encDataFunc(inData, inDataLen, outData, &outDatalen, NULL, 0);
    		if (rv != 0)
    		{
    			printf("edf err .....
    ");
    		}
    		else
    		{
    			printf("edf ok 
    ");
    			printf("%s 
    ", outData);
    		}
    	}
    
    	{
    		unsigned char inData[2048];
    		int inDataLen;
    		unsigned char outData[2048];
    		int outDatalen;
    		strcpy(inData, "3333");
    		inDataLen = strlen(inData);
    		rv = Send_Data(MyEncDataFunc, inData, inDataLen, outData, &outDatalen);
    		if (rv != 0)
    		{
    			printf("func Send_Data err:%d", rv);
    			return rv;
    		}
    		printf("%s 
    ", outData);
    	}
    
    	getchar();
    }
    

    函数指针反向调用

    利用函数指针实现的一种调用机制
    具体任务的实现者,可以不知道什么时候被调用
    回调函数是利用函数指针实现的一种调用机制

    回调机制原理

    • 当具体事件发生时,调用者通过函数指针调用具体函数
    • 回调机制的将调用者和被调函数分开,两者互不依赖
    • 任务的实现和任务的调用可以耦合(提前进行接口的封装和设计)

    需要重新审视 dll和其他第三方厂商 接口之间的关系

    • 动态库可以集成第三方厂商的业务功能
    • 动态库(框架)不经常改动,能兼容后来的业务模型
    • 动态库和第三方业务模型 模块之间 松耦合

    动态库变成框架,需要做的工作

    1. 第三方业务入口传进来(回调函数的入口地址传进来)
    2. 加密 解密 业务模型抽象
      实现动态库加密解密业务模型抽象
      通过定义函数指针类型;函数指针做函数参数实现
  • 相关阅读:
    线程池的工作原理
    并发处理之master-worker 模式
    Parrot os引导修复
    使用datax mongodb导数据到postgresql数据库遇到访问权限问题
    10、Flink高可用HA
    9、Standalone集群测试运行
    8、Flink Standalone工作流程
    7、Flink Local模式安装部署
    java读取word文档的文字内容
    对文件内容就行修改-java代码
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664756.html
Copyright © 2011-2022 走看看