欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

函数指针的强制类型转换与void指针

程序员文章站 2022-07-12 16:51:06
...

前两天在移植一个DVB芯片的驱动库时,遇到一个情况:
驱动库的作者为了使DVB芯片兼容尽可能多的tuner芯片,在定义tuner_init函数指针时,参数中的handle定义为(void* handle)。这样的话,这个handle既可以接收tuner1_handle ,也可以接收tuner2_handle。同时函数指针tuner_init也可以指向tuner1和tuner2各自的初始化函数地址。
但原作者在进行这种参数类型不同的函数指针赋值时,没有采用强制类型转换,导致编译器报出大量警告,甚至有些编译器会直接报错(不知道原作者用的什么编译器,这么皮。。。)。为此,我查了一些关于函数指针强制类型转换和void指针的资料。


函数指针普通用法

先来个无软用的VS2013示例代码:

#include "stdafx.h"

/* 真实函数fun_int */
void fun_int(int *p_fun)
{
    printf("整数:%d\n", *p_fun);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int i = 200;    /* 真实整数变量 */
    int* p_i = &i;  /* 整数指针 */

    void (*f_ptr)(int *p_fun);  /* 函数指针 */
    f_ptr = fun_int;    /* 函数指针赋值 */
    f_ptr(p_i);
    return 0;
}

运行结果如下:
函数指针的强制类型转换与void指针

总之就是,定义一个包含返回值类型和参数的函数指针,然后把一个返回值类型,参数类型及个数都相同的函数名(即地址)赋值给这个函数指针,这个函数指针就可以当成普通函数用了。

函数指针强制类型转换

此处只展示一种情况:函数指针和真实函数的返回值及参数个数都相同,只有参数类型不同。


/* 真实函数fun_float */
void fun_float(float *p_fun)
{
    printf("小数:%f\n", *p_fun);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int i = 20000;  /* 真实整数变量 */
    int* p_i = &i;  /* 整数指针 */

    float f = 9.999f;   /* 真实浮点变量 */
    float* p_f = &f;    /* 浮点指针 */

    void (*f_ptr)(int *p_fun);  /* 函数指针 */
    f_ptr = (void (*)(int *))fun_float; /* 函数指针强制类型转换 */
    f_ptr(p_i);       /* 传入int指针 */
    f_ptr((int *)p_f);/* 传入float指针 */
    return 0;
}

运行结果如下:
函数指针的强制类型转换与void指针
此时我们可以发现一件有趣的事情:尽管函数指针f_ptr的参数是int,但传入的int指针打印数据不正常(正常为20000),而类型不匹配的float指针却是对的(9.999)。
对此我总结了两点:

  1. 函数指针的指针参数只是一个标记(或者说只是一个保存指针的地址?),总之其类型更多是为了编译器检查以及代码可读性,实际工作时只要产生强制类型转换之后,其类型就没有意义了,只是单纯的一个指针而已。
  2. 我们在使用函数指针时,需要保证调用该指针时的入参与该指针指向的真实函数的入参保持一致。

以void指针作为参数的函数指针

结合之前的结论,在函数指针中包含指针参数时,都可以用void指针进行替代(如果类型很明确就另当别论了)。

/* 真实函数fun_int */
void fun_int(int *p_fun)
{
    printf("整数:%d\n", *p_fun);
}

/* 真实函数fun_float */
void fun_float(float *p_fun)
{
    printf("小数:%f\n", *p_fun);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int i = 20000;  /* 真实整数变量 */
    int* p_i = &i;  /* 整数指针 */

    float f = 9.999f;   /* 真实浮点变量 */
    float* p_f = &f;    /* 浮点指针 */

    void (*f_ptr)(void *p_fun); /* 函数指针 */
    f_ptr = (void (*)(void *))fun_int;  /* 强制为void* */
    f_ptr(p_i);
    f_ptr = (void(*)(void *))fun_float; /* 强制为void* */
    f_ptr(p_f);
    return 0;
}

运行结果如下:
函数指针的强制类型转换与void指针
如此一来,只需要在函数指针赋值时进行强制类型转换就可以适应不同的真实函数。在调用时只要保证以void指针作为参数的函数指针结论中的第2点即可。


至此,博主于函数指针中指针参数的理解可能还会存在一些偏差,也欢迎各位大佬指正。
此外推荐另外一位博主的文章《关于函数指针类型强制转换的一些摸索》,在函数指针的参数传递上有更深的理解,也给这篇博文以很多的启发。