C语言的声明是让初学者最为头疼的地方之一,本文提供一种理解C语言声明的方法之一,仅供参考。
要理解一个声明,必须要懂得其中的优先级规则。以下提供一个优先级规则
A 声明从它的名字开始读取,然后按照优先级顺序依次读取
B 优先级从高到低依次是:
B 1声明中被括号括起来的那部分
B 2后缀操作符:括号()表示这是一个函数,而方括号[]表示这是一个数组
B 3前缀操作符:星号*表示"指向...的指针"
C 如果const和(或) volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符。在其它情况下,const和(或) volatile关键字作用于它左边紧邻的指针星号
以下是一个例子:
char * const *(*next)();
按照规则,我们先看变量名"next",并注意到它直接被括号所括住,所以先把括号里的东西作为一个整体,得出"next是一个指向...的指针",然后考虑括号外面的东西,在星号前缀和括号后缀之间作出选择,B2规则告诉我们优先级较高的是右边的函数括号,所以得出"next是一个函数指针,指向一个返回...的函数",然后,处理前缀"*",得出指针所指的内容,最后,把"char * const"解释为指向字符的常量指针。
将以上分析结果加以概括,这个声明表示"next是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针",大功告成。
另外附一个将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 thistoken;
#define pop stack[top--]
#define push(s) stack[++top]=s
/*推断标识符类型*/
enum type_tag classify_string(void)
{
char *s=thistoken.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,"long"))
return TYPE;
if(!strcmp(s,"float"))
return TYPE;
if(!strcmp(s,"double"))
return TYPE;
if(!strcmp(s,"struct"))
return TYPE;
if(!strcmp(s,"enum"))
return TYPE;
if(!strcmp(s,"union"))
return TYPE;
return IDENTIFIER;
}
/*读取下一个标记到"thistoken"*/
void gettoken(void)
{
char *p=thistoken.string;
/*略过空白字符*/
while((*p=getchar())==' ')
;
if(isalnum(*p)){
while(isalnum(*++p=getchar()))
;
ungetc(*p,stdin);
*p='/0';
thistoken.type=classify_string();
return;
}
if(*p=='*'){
strcpy(thistoken.string,"pointer to");
thistoken.type='*';
return;
}
thistoken.string[1]='/0';
thistoken.type=*p;
return;
}
/*理解所有分析过程的代码段*/
void read_to_first_identifier(){
gettoken();
while(thistoken.type!=IDENTIFIER){
push(thistoken);
gettoken();
}
printf("%s is ",thistoken.string);
gettoken();
}
void deal_with_arrays(){
while(thistoken.type=='['){
printf("array ");
gettoken();
/*数字或中括号*/
if(isdigit(thistoken.string[0])){
printf("0..%d ",atoi(thistoken.string)-1);
gettoken(); /*读取']' */
}
gettoken(); /*读取']'之后的再一个标记*/
printf("of ");
}
}
void deal_with_function_args(){
while(thistoken.type!=')'){
gettoken();
}
gettoken();
printf("function returning ");
}
void deal_with_pointers(){
while(stack[top].type=='*'){
printf("%s ",pop.string);
}
}
void deal_with_declarator(){
/*处理标识符之后可能存在的数组/函数*/
switch(thistoken.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);
}
}
}
int main()
{
/*将标记压入堆栈,直到遇见标识符*/
read_to_first_identifier();
deal_with_declarator();
printf("/n");
return 0;
}