问题:

在刚接触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);

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

#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)…正是这样的格式。

在阅读《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);

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

更多参考

最新文章

  1. angular-route 和soket注意细节点
  2. Linux下安装VMware Tools 的方法
  3. jquery设置元素的readonly和disabled
  4. Leetcode Evaluate Reverse Polish Notation
  5. OPTIMIZE TABLE的作用--转载
  6. [Tool] 源代码管理之Git
  7. js禁止复制页面文字
  8. RabbitMQ 一二事(4) - 路由模式介绍
  9. JAVA中的定时调度(Timer和TimerTask)
  10. MongoDB的启动
  11. CN今日凌晨出现全部瘫痪的故障,持续近6个小时
  12. 巧用九宫格以减少UI资源量
  13. 统一Matlab下不同子图的色标colorbar
  14. Selenium WebDriver + Grid2 + RSpec之旅(六) ----多浏览器的并行执行
  15. Android含文档server结束(client UI接口异步请求的一部分)三
  16. CocoaPods安装和使用及问题----看过写的最好的
  17. ionic2 跳转子页面隐藏底部导航栏
  18. 机房收费系统——转换list泛型时,字段名称不正确应出现故障
  19. Liunx中三种网络模式配置及Xshell连接
  20. MQ基本概念

热门文章

  1. react+redux+react-router+node.js 开发实时聊天App 学习记录
  2. [转载]window.location.href的用法(动态输出跳转)
  3. TensorFlow for distributed
  4. 几张图看明白VAO、VBO、EBO的关系和代码顺序
  5. 监控nginx服务
  6. jpg、gif、png-8、png-24的区别
  7. The Little Prince-12/05
  8. spring总结之三(依赖注入)
  9. php 阳历转农历优化版
  10. 远程图片转化为base64