问题:

在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一“块”东西,而不是两“块”东西呢?那是谁“替代”了谁啊?我总结了一下,一方面是对typedef的概念不清晰,另一方面受了#define的影响,犯了定向思维的错误。

概念理解:

typedef 只对已有的类型进行别名定义,不产生新的类型;

#define 只是在预处理过程对代码进行简单的替换。

清晰了解两个概念后,发现它们就是两个不同的概念,并没有太多的联系。

类比理解:

typedef  unsigned int  UINT32;  // UINT32 类型是unsigned int

UINT32 sum;                                 // 定义一个变量:int sum;

typedef  int  arr[3];                     // arr 类型是 int[3];(存放int型数据的数组)

arr a;                                              // 定义一个数组:int a[3];

同理:

typedef  void (*pfun)(void);         // pfun 类型是 void(*)(void)

pfun main;                                       // 定义一个函数:void (*main)(void);

在博客上看到一个经典的函数指针用例:

为保护原创作者的权益,以下例子代码不作修改:

<来源网址:http://www.cnblogs.com/shenlian/archive/2011/05/21/2053149.html>

#include<stdio.h>

typedef int (*FP_CALC)(int, int);

//注意这里不是函数声明而是函数定义,它是一个地址,你可以直接输出add看看

int add(int a, int b)

{

return a + b;

}

int sub(int a, int b)

{

return a - b;

}

int mul(int a, int b)

{

return a * b;

}

int div(int a, int b)

{

return b? a/b : -1;

}

//定义一个函数,参数为op,返回一个指针。该指针类型为 拥有两个int参数、

//返回类型为int 的函数指针。它的作用是根据操作符返回相应函数的地址

FP_CALC calc_func(char op)

{

switch (op)

{

case '+' : return add;   // 返回函数的地址

case '-' : return sub;

case '*' : return mul;

case '/' : return div;

default:

return NULL;

}

return NULL;

}

//s_calc_func为函数,它的参数是 op,返回值为一个拥有两个int参数、返回类型为int 的函数指针

int (*s_calc_func(char op)) (int, int)

{

return calc_func(op);

}

//最终用户直接调用的函数,该函数接收两个int整数,和一个算术运算符,返回两数的运算结果

int calc(int a, int b, char op)

{

FP_CALC fp = calc_func(op);                  // 根据预算符得到各种运算的函数的地址

int (*s_fp)(int, int) = s_calc_func(op);  // 用于测试

// ASSERT(fp == s_fp);                          // 可以断言这俩是相等的

if (fp)

return fp(a, b);  //根据上一步得到的函数的地址调用相应函数,并返回结果

else

return -1;

}

void main()

{

int a = 100, b = 20;

printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));

printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));

printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));

printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));

}

结合代码理解:

代码作者在注释中表述得很清楚,个人觉得最有意思就是一下这个函数:

FP_CALC calc_func(char op)    <-->   int (*calc_func(char op)) (int, int)

  代码作者试图在断言中说明这个关系,相比较,还是FP_CALC calc_func(char op)函数更能表达编码者的意图:calc_func函数返回FP_CALC类型的指针,是一个函数指针,这个函数的形式是int (函数名)(int, int),代码中int add(int a, int b)、int sub(int a, int b)…正是这样的格式。

(修改于 2016-12-22  19:23:37)

在阅读《C和指针》的时候,我猛然想起还有一个东西叫“函数指针数组”,也就是书中所描述的新概念:转移表。

下面是实现一个简易计算器的核心代码:

 switch(oper){
  case ADD:
    result = add(oper1, oper2);
    break;   case SUB:
    result = sub(oper1, oper2);
    break;   case MUL:
    result = mul(oper1, oper2);
    break;   case DIV:
    result = div(oper1, oper2);
    break;
  ……
}

这是一种我们常用的实现方式,在书中提到有一个最起码看起来更高端,更简洁的方法:

 double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);
……
Double (*oper_fun[])(double, double) = {add, sub,mul,div,…};
调用时:
result = oper_func[oper](oper1, oper2);

为什么要调用函数来执行这些操作呢?把具体操作和选择操作的代码分开是一种良好的设计方案。

——《C和指针》

如何理解typedef void (*pfun)(void)的更多相关文章

  1. 函数指针-如何理解typedef void (*pfun)(void)

    问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...

  2. NRF51822+STM32bootload——typedef void (*Fun) (void) 理解

    1.typdef 用法如下所示 typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned ...

  3. typedef int(init_fnc_t) (void)的理解

    typedef int(init_fnc_t) (void); 这个就是一个取别名的过程. 我们通常情况下会如下使用 typedef :typedef int MyInt;MyInt a; 这个时候我 ...

  4. typedef interrupt void (*PINT)(void)的分析

    今天写程序时,在DSP2833x_PieVect.h看到typedef interrupt void (*PINT)(void)突然一愣,上网查了下发现在这是加了interrupt 中断关键字的函数指 ...

  5. typedef int (init_fnc_t) (void)和typedef int (*init_fnc_t) (void)

    1.typedef  int (init_fnc_t) (void);表示定义init_fnc_t为函数类型,该函数返回int型,无参数.而“init_fnc_t  *init_sequence[]= ...

  6. typedef void (*funcptr)(void)

    定义一个函数指针类型.比如你有三个函数:void hello(void) { printf("你好!"); }void bye(void) { printf("再见!&q ...

  7. “typedef int (init_fnc_t) (void);“的含义

    在读uboot的lib_arm/board.c中的start_armboot ()函数遇到了"init_fnc_t **init_fnc_ptr;”一句话,后来查看init_fnt_t数据类 ...

  8. typedef void(*Fun)(void);

    typedef void(*Fun)(void); 函数类似于数组,函数名就是它的首地址: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ...

  9. typedef void(*Func)(void)的简单用途

    typedef void(*Func)(void)的用途 用法的好处: 定义一个函数指针类型. 例子: 有三个类型相似或功能相似的函数: void TASK1(void) { printf(" ...

随机推荐

  1. acm的ubuntu (ubuntu16.04 安装指南,chrome安装,vim配置,git设置和github,装QQ)

    日常手贱把ubuntu14.04更新到了16.04,然后就game over了.mdzz,不然泥萌也看不到这篇博客了=.= 然后花了些时间重装了一个16.04版的,原来那个14.04的用可以用,就是动 ...

  2. How to use Bundle&Minifier and bundleconfig.json in ASP.NET Core

    引言 我们在ASP.NET MVC 中经常会用到 bundleConfig.cs 文件来进行我们 css 和 js 的绑定, 那么在ASP.NET Core 中我们应该如何使用呢? 步骤一 在 Vis ...

  3. Volley框架使用笔记

    1.初始化请求队列 RequestQueue RequestQueue queue= Volley.newRequestQueue(context); 2.StringRequest 网络请求 Get ...

  4. .htaccess中Apache配置详解

    1.<IfDefine> 指令 说明 封装一组只有在启动时当测试结果为真时才生效的指令 语法 <IfDefine [!]parameter-name> ... </IfD ...

  5. 引用类型的转换问题和instanceof

    基本数据类型:  

  6. curl及postman专题

    一. 步骤 1: 下载cURL工具 使用您的Windows机器从cURL web站点下载最新版本的cURL: (1) 通常情况下,多数的Windows用户可以从官网下载页面http://curl.ha ...

  7. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  8. extern "c"用法解析

    转自: extern "c"用法解析 - 简书 引言 C++保留了一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数.但是,C++毕竟是一种面向对象的程序设计语言, ...

  9. 设计模式--桥接模式Bridge(结构型)

    一.概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或者多个维度的变化,如何应对这种"多维度的变化",就可以利用桥接模式. 引例: 设想如果要绘制矩形.圆形.椭圆.正方形,我 ...

  10. iOS 对象的内存管理细节

    通过类创建对象 1.创建对象时,开辟存储空间,通过new方法创建的对象会在 堆 内存中开辟一块存储空间 2初始化所有属性都在堆内存中完成 3.返回值真地址,指针在栈内存中,指针指向的地址是堆里创建对象 ...