优先级规则分析
A.声明从他的第一个标识符(名字)开始读取,然后按照优先级顺序依次读取:
B 优先级从高到低依次是:
B.1声明中被括号括起来的那部分
B.2后缀操作符:
括号()表示这是一个函数,而方括号[]表示这是一个数组。
B.3前缀操作符:星号*表示“指向...的指针”
C 如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等),那么它用做子类型说明符。在其他情况下, const和(或)volatile关键字作用于它左边的临近的指针星号。
例:
char * const *(*next)();
A 首先,看变量名(标识符)“next”,并注意到它直接被括号所括住
B.1 所以先把括号里的东西作为一个整体,得出“next是一个指向...的指针”
B 然后考虑括号外面的东西,在星号前缀和括号后缀之间作出选择
B.2 B.2规则告诉我们优先级较高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回...的函数”
B.3 然后,处理前缀“*”,得出指针所指的内容
C 最后,把“char * const”解释为指向字符的常量指针
更直观一点可以看下图
所以这个声明表示“next”是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针。
例子2 char *(* c[10]) (int **p)
剩余的声明 |
下一次要进行的步骤 |
结果 |
从最左边的标识符开始 |
|
|
char *(* c[10])(int **P) |
1 |
表示c是一个x |
char *(* [10])(int **P) |
2 |
表示x的数组[0~9] |
char *(* )(int **P) |
3 |
表示指向x的指针 |
char *( )(int **P) |
4 |
表示返回y的函数,且参数是指向指针的指针 |
char * |
5 |
表示指向char的指针 |
那么合起来就是c是一个函数指针数组,他的返回类型是char *,参数是int **p
以下是来自c专家编程的一个分析声明的程序
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag { IDENTIFIER, QUALIFIER, TYPE};
struct token{
char type;
char string[MAXTOKENLEN];
};
int top = -1;
struct token stack[MAXTOKENS];
struct token this;
#define pop stack[top--]
#define push(s) stack[++top] = s
enum type_tag classify_string(void)
{
char *s = this.string;
if ( !strcmp(s,"const"))
{
strcpy(s,"read-only");
return QUALIFIER;
}
if (!strcmp(s,"volatile"))
return QUALIFIER;
if (!strcmp(s,"void"))
return TYPE;
if (!strcmp(s,"char"))
return TYPE;
if (!strcmp(s,"signed"))
return TYPE;
if (!strcmp(s,"unsigned"))
return TYPE;
if (!strcmp(s,"short"))
return TYPE;
if (!strcmp(s,"int"))
return TYPE;
if (!strcmp(s,"void"))
return TYPE;
if (!strcmp(s,"long"))
return TYPE;
if (!strcmp(s,"float"))
return TYPE;
if (!strcmp(s,"double"))
return TYPE;
if (!strcmp(s,"struct"))
return TYPE;
if (!strcmp(s,"union"))
return TYPE;
if (!strcmp(s,"enum"))
return TYPE;
return IDENTIFIER;
}
void gettoken(void)
{
char *p = this.string;
while((*p = getchar() ) == ' ');
if ( isalnum(*p) )
{
while( isalnum( *++p = getchar() ));
ungetc(*p , stdin);
*p = '/0';
this.type = classify_string();
return;
}
if (*p == '*' )
{
strcpy(this.string, "pointer to");
this.type = '*';
return;
}
this.string[1] = '/0';
this.type = *p;
return;
}
read_to_first_identifer()
{
gettoken();
while(this.type != IDENTIFIER )
{
push( this );
gettoken();
}
printf("%s is ",this.string);
gettoken();
}
deal_with_arrays()
{
while(this.type = '[' )
{
printf("array");
gettoken();
if ( isdigit(this.string[0]) )
{
printf("0..%d ",atoi(this.string)-1);
gettoken();
}
gettoken();
printf("of ");
}
}
deal_with_function_args()
{
while( this.type != ')' )
{
gettoken();
}
gettoken();
printf("function returning ");
}
deal_with_pointers()
{
while(stack[top].type == '*' )
{
printf("%s ", pop.string);
}
}
deal_with_declarator()
{
switch(this.type)
{
case '[' :deal_with_arrays();break;
case '(' :deal_with_function_args();
}
deal_with_pointers();
while( top >= 0 )
{
if ( stack[top].type == '(' )
{
pop;
gettoken();
deal_with_declarator();
}
else
printf("%s ",pop.string);
}
}
main()
{
read_to_first_identifer();
deal_with_declarator();
printf("/n");
return 0;
}