zoukankan      html  css  js  c++  java
  • 如何理解typedef void (*pfun)(void)

    问题:

          在刚接触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 ", a, b, '+', calc(a, b, '+'));

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

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

          printf("calc(%d, %d, %c) = %d ", 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和指针》的时候,我猛然想起还有一个东西叫“函数指针数组”,也就是书中所描述的新概念:转移表。

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

     1 switch(oper){
     2   case ADD:
     3     result = add(oper1, oper2);
     4     break;
     5 
     6   case SUB:
     7     result = sub(oper1, oper2);
     8     break;
     9 
    10   case MUL:
    11     result = mul(oper1, oper2);
    12     break;
    13 
    14   case DIV:
    15     result = div(oper1, oper2);
    16     break;
    17   ……
    18 }

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

    1 double add(double, double);
    2 double sub(double, double);
    3 double mul(double, double);
    4 double div(double, double);
    5 ……
    6 Double (*oper_fun[])(double, double) = {add, sub,mul,div,…};
    7 调用时:
    8 result = oper_func[oper](oper1, oper2);

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

    ——《C和指针》

     

  • 相关阅读:
    NET Core入门笔记
    NET Core入门笔记
    NET Core入门笔记
    也许,这样理解HTTPS更容易
    也许,这样理解HTTPS更容易
    也许,这样理解HTTPS更容易
    10 个实战及面试常用 Shell 脚本编写
    10 个实战及面试常用 Shell 脚本编写
    10 个实战及面试常用 Shell 脚本编写
    7617:输出前k大的数
  • 原文地址:https://www.cnblogs.com/guanguangreat/p/6117988.html
Copyright © 2011-2022 走看看