zoukankan      html  css  js  c++  java
  • C专家编程(2)

    理解声明(P64-66)

    面对一些复杂的声明形式,可以通过以下两种方法来理解,分别是优先级法和图标法。下面以书上的
    char * const *(*next)(); 为例,分别进行分析。

    • 优先级法(P64)

    适用规则 解释
    A 首先,看变量名next,并注意到它直接被括号所括住
    B.1 所以先把括号里的东西作为一个整体,得出“next是一个指向...的指针”
    B 然后考虑括号外面的东西,在星号前缀和括号后缀之间作出选择
    B.2 规则告诉我们优先级较高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回...的函数"
    B.3 然后,处理前缀*,得出指针所指的内容
    C 最后,把char * const解释为指向字符的常量指针

    这个声明表示“next是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为 char的常量指针”

    • 图表法(P65)

    signal函数声明的解析

    首先来看一下signal的声明形式:

    void (*signal(int sig, void(*func)(int)))(int);
    

    简化后为void(*signal(x,xx))(int),表明signal函数有两个参数(x和xx),并返回一个函数指针,指向的函数接受int类型的参数并返回void。而xx参数表示的函数与signal本身的形式一样。

    因此可以使用typedef void(*pf)(int);来简化函数的声明,简化后为:pf signal(int, pf);

    练习

    char *(* c[10])(int **p);  // 答案在文章末尾
    

    编程挑战

    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTOKENLEN (256)
    #define MAXTOKENS (16)
    #define TOTAL_NUMS(array) (sizeof(array) / sizeof(array[0]))
    
    char *STR_TYPE[] = {"char",   "short",    "int",  "long",   "float", "double",
                        "signed", "unsigned", "void", "struct", "union", "enum"};
    char *STR_QUALIFIER[] = {"const", "volatile"};
    
    typedef enum {
      TYPE,       /* 类型 */
      QUALIFIER,  /* 限定符 */
      INDENTIFIER /* 标识符 */
    } type_t;
    
    struct token {
      char type;
      char string[MAXTOKENLEN];
    };
    
    struct token stack[MAXTOKENS]; /* 保存第一个标识之前的所有标记 */
    struct token this;             /* 保存刚读入的标记 */
    char next_string[MAXTOKENLEN];
    
    int top = -1; /* 栈顶 */
    // 压栈
    static void push(struct token t) { stack[++top] = t; }
    // 出栈
    static struct token pop(void) { return stack[top--]; }
    
    // 字符串分类,获取当前标识的类型
    static type_t classify_string(void) {
      int i = 0;
      char *s = this.string;
    
      for (i = 0; i < (int)TOTAL_NUMS(STR_TYPE); i++) {
        if (strcmp(s, STR_TYPE[i]) == 0) {
          return TYPE;
        }
      }
      for (i = 0; i < (int)TOTAL_NUMS(STR_QUALIFIER); i++) {
        if (strcmp(s, STR_QUALIFIER[i]) == 0) {
          return QUALIFIER;
        }
      }
      return INDENTIFIER;
    }
    
    // 获取标记
    static void gettoken(void) {
      char *p = next_string; /* 取新的一段字符串 */
    
      while (*p == ' ') { /* 忽略空格 */
        p++;
      }
      strcpy(this.string, p); /* 字符串赋值 */
      p = this.string;
    
      if (isalnum(*p)) { /* 如果是字母数字组合 */
        while (isalnum(*++p))
          ;                                  /* 直到读取到其他字符 */
        strcpy(next_string, p);              /* 修改字符串 */
        *p = '';                           /* 加上字符串结束符 */
        this.type = (char)classify_string(); /* 判断类型 */
      } else if (*p != '') {               /* 单字符标记 */
        strcpy(next_string, p + 1);          /* 修改字符串 */
        this.type = *p;
        this.string[1] = '';
      }
    }
    
    // 读至第一个标识符
    static void read_to_first_identifier(void) {
      gettoken();
      while (this.type != INDENTIFIER) /* 不是标识符,将标记入栈 */
      {
        push(this);
        gettoken(); /* 取下一个标记 */
      }
    
      printf("Identifier "%s" is ", this.string);
    
      gettoken();
    }
    
    /*************** 解析程序 ***************************************/
    // 处理函数参数
    static void deal_with_function_args(void) {
      while (this.type != ')') {
        gettoken();
      }
      gettoken();
      printf("function returning ");
    }
    
    // 处理函数数组
    static void deal_with_arrays(void) {
      while (this.type == '[') /* 继续读取数字或']' */
      {
        printf("array ");
        gettoken();
        if (isdigit(this.string[0])) {             /* 如果是数字 */
          printf("0..%d ", atoi(this.string) - 1); /* 打印数组大小 */
          gettoken();                              /* 获取']' */
        }
        gettoken();
        printf("of ");
      }
    }
    
    // 处理任何指针
    static void deal_with_any_pointers(void) {
      while (stack[top].type == '*') {
        pop();
        printf("pointer to ");
      }
    }
    
    // 处理声明器
    static void deal_with_declarator(void) {
      if (this.type == '[') {
        deal_with_arrays();
      } else if (this.type == '(') {
        deal_with_function_args();
      }
    
      deal_with_any_pointers();
    
      while (top > -1) {
        if (stack[top].type == '(') {
          pop();
          gettoken();
          deal_with_declarator();
        } else {
          deal_with_any_pointers();
          printf("%s ", pop().string);
        }
      }
    }
    
    int main(void) {
      // 测试用例参考 https://blog.csdn.net/yyhustim/article/details/9612185
      char *str[] = {"char * const *(*next)()", "char *(* c[10])(int **p)",
                     "const int * grape",       "int const * grape",
                     "int * const grape",       "int sum(int a, int b)",
                     "char (*(*x())[])()",      "char (*(*x[3])())[5]"};
      for (int i = 0; i < (int)TOTAL_NUMS(str); i++) {
        printf("== %s
    ", str[i]);
        strcpy(next_string, str[i]);
        read_to_first_identifier();
        deal_with_declarator();
        printf("
    
    ");
        top = -1;
      }
    
      return 0;
    }
    

    答案

    运行上面的程序,给出的结果为:

    Identifier "c" is array 0..9 of pointer to function returning pointer to char

    即c是一个大小为10的数组,其元素类型是函数指针,指向的函数的返回值是一个指向char的指针。

  • 相关阅读:
    跨域资源共享 CORS 详解
    C# 每月第一天和最后一天
    jexus http to https
    ASP.NET MVC 路由学习
    jexus
    centos7 添加开机启动项
    jexus docker
    HTTP2.0新特性
    jexus配置支持Owin
    Autofac Named命名和Key Service服务
  • 原文地址:https://www.cnblogs.com/maxiaowei0216/p/14247490.html
Copyright © 2011-2022 走看看