C专家编程(2)
|字数总计:1.2k|阅读时长:5分钟|阅读量:|
理解声明(P64-66)
面对一些复杂的声明形式,可以通过以下两种方法来理解,分别是优先级法和图标法。下面以书上的
char * const *(*next)();
为例,分别进行分析。

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


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 = '\0'; this.type = (char)classify_string(); } else if (*p != '\0') { strcpy(next_string, p + 1); this.type = *p; this.string[1] = '\0'; } }
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) { 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\n", str[i]); strcpy(next_string, str[i]); read_to_first_identifier(); deal_with_declarator(); printf("\n\n"); top = -1; }
return 0; }
|
答案
运行上面的程序,给出的结果为:
Identifier "c" is array 0..9 of pointer to function returning pointer to char
即c是一个大小为10的数组,其元素类型是函数指针,指向的函数的返回值是一个指向char的指针。