Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65764
  • 博文数量: 7
  • 博客积分: 347
  • 博客等级: 二等列兵
  • 技术积分: 127
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-26 17:18
个人简介

一句话介绍是什么?

文章分类

全部博文(7)

分类: C/C++

2011-01-26 17:57:06

这是一篇针对于C语言新手的文章,能够让你轻松的阅读C语言那恐怖的声明形式。

-------------------------------------------------------------------------------------
C语言声明的阅读方法:
找到声明的标识符,然后按照优先级规则进行读取
        优先级:  1. 包含标识符的括号里的部分
                        2. 先看标识符(如果标识符包含在括号中则看括号)后面的
后缀
                                如果是小括号“()”则表示这是一个函数;
                                如果是方括号“[]”则表示这是一个数组。
                        3. 再看标识符(如果标识符包含在括号中则看括号)前面的
前缀
                                如果有星号“*”则表示这是一个指向……的指针。
注意:关键字const 和volatile 修饰的永远是它左边的东西,如果这两个关键字本身就在声明的最左边,那么它们就“只好”修饰右边的东西。
------------------------------------------------------------------------------------
现在让我们拿signal 函数的声明开个小刀 ;p
signal 的声明是:
  1. void (*signal(int signum,void (* handler)(int)))(int);
看起来有点惊心动魄?别怕,只要学会了上面的声明阅读方法再复杂的声明也轻松搞定 ;p

==================开始分析=================
找到声明的标识符signal,按照优先级规则读取。
先看包含标识符的括号里的部分:
        先看后缀,signal 后面有小括号“()”,表示signal 是一个函数,括号里是一些参数。于是声明简化为:
  1. void (*signal())(int);
        再看前缀,signal 的左边是星号“*”,表示signal 的返回值是一个指针。
看标识符所在括号外面的部分:
        先看后缀,后面是小括号“()”,则表示signal 返回的指针指向一个函数。
                看这个小括号里面是关键字int, 表示signal 返回的指针指向的函数有一个int 型参数。
        再看前缀,前面是关键字void ,则表示signal 返回的指针所指向的函数无返回值。
让我们把上面的分析综合起来:
signal 是一个带参数的函数,返回一个指向以一个int 型变量做参数、无返回值的函数的指针。

好了,接着处理signal 的参数:
  1. int signum,void (* handler)(int)
先看第一个声明,找到标识符signum,只有一个用来修饰它的前缀int,则表示signum 是一个int 变量。
再看第二个声明,找到标识符 handler。
        首先看标识符所在括号里的部分,只有一个用来修饰它的前缀星号“*”,表示handler 是一个指针。
        再看标识符所在括号外面的后缀,发现小括号“()”,handler 指针指向一个函数。
                看这个小括号“()”里面的部分,发现有一个关键字int, 则表示这个函数接受一个int 型参数。
        接着看标识符所在括号外面的前缀,发现是关键字void,表示handler 指针指向的函数无返回值。
让我们把上面的分析综合起来:
signum 是一个int 型变量,handler 是一个指向接受一个int 型参数、无返回值的函数的指针。
接着,我们把两部分的分析结果再做综合:
  1. void (*signal(int signum,void (* handler)(int)))(int);
的意思就是:signal 是一个函数。它的参数有两个:一个是int 型变量,另一个是一个函数指针,这个函数指针指向一个接受一个int 型参数、无返回值的函数。它的返回值是一个函数指针,指向的函数接受一个int 型参数、无返回值。
大功告成!
==================结束分析=================

下面给你个东西让你练练手 ;p
写一个函数指针,指向一个接受一个函数指针作为参数返回一个函数指针的函数
。并用一个适当的main 函数版本来演示它的运行。

下面的代码是一种实现方法,不过你最好自己写完后再来看它 ;p

  1. /* * * * * * * * * * * * * * * * * * * * *
  2.  * pfunc是一个函数指针,指向一个接受
  3.  * 一个函数指针做参数并返回一个函数指针的函数
  4.  */

  5. #include <stdio.h>

  6. void (*func (void (*) (void))) (void);
  7. void func2 (void);

  8. int main
  9. (void) {
  10.         
  11.         void (*(*pfunc) (void (*) (void))) (void) = NULL;
  12.         void (*pfunc2) (void) = NULL;
  13.         void (*pfunc_tmp) (void) = NULL;
  14.         
  15.         pfunc2 = func2;
  16.         pfunc = func;
  17.         pfunc_tmp = *(*pfunc) (pfunc2);
  18.         (*pfunc_tmp) ();
  19.         puts ("Press ENTER to quit.\n");
  20.         getchar ();
  21.         
  22.         return 0;
  23. }

  24. void (*func (void (*pfunc) (void)))
  25. (void) {
  26.         puts ("Though func.\n");
  27.         (*pfunc) ();
  28.         
  29.         return pfunc;
  30. }

  31. void func2
  32. (void) {
  33.         
  34.         puts ("Though func2.\n");
  35.         
  36.         return;
  37. }
原本恐怖的C语言声明,现在看来是不是很简单呢 ? ;p


---------------补充点东西------------------
下面是09年从c专抄的,99%纯手工抄,不过机器分析很爽
  1. /*
  2. cdecl程序,用于分析C语言的声明
  3. */

  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. #define STRCMP(a, R, b) (strcmp(a, b) R 0)
  9. #define MAXTOKENS 100
  10. #define MAXTOKENLEN 64

  11. enum type_tag{ Identifer, Qualifier, Type };

  12. struct token
  13. {
  14.   char type;
  15.   char string[MAXTOKENLEN];
  16. };
  17. struct token stack[MAXTOKENS];
  18. struct token this;
  19. int top = -1;

  20. #define pop stack[top--]
  21. #define push(s) stack[++top] = s

  22. void Read_to_first_identifer(void);
  23. enum type_tag Classify_str(void); /*推断标识符的类型*/
  24. void Gettoken(void);/*读取下一个标记到this*/
  25. void Deal_with_declarator(void);
  26. void Deal_with_arrays(void);
  27. void Deal_with_function_args(void);
  28. void Deal_with_pointers(void);
  29. void Deal_wirh_declarator(void);


  30. int main(void)
  31. {
  32.   char next = 0;
  33.   printf("输入一个C语言声明,cdecl程序会把声明转化成通俗文字:\n");
  34.   do{
  35.     /*将标记压入堆栈,直至遇到标识符*/
  36.     Read_to_first_identifer();
  37.     Deal_with_declarator();
  38.     printf("\n是否进行下一个声明的推断(y\\n)?");
  39.   }while('Y' == toupper( next = getchar() ));
  40.   return 0;
  41. }

  42. void Read_to_first_identifer(void)
  43. {
  44.   Gettoken();
  45.   while(Identifer != this.type)
  46.   {
  47.     push(this);
  48.     Gettoken();
  49.   }
  50.   printf("%s is ", this.string);
  51.   Gettoken();
  52.   return;
  53. }

  54. void Gettoken(void)
  55. {
  56.   char *p = this.string;
  57.   
  58.   while( ' ' == (*p = getchar()) );/*忽略空格*/
  59.   
  60.   if(isalnum(*p))/*A~z,0~9*/
  61.   {
  62.     while(isalnum( *++p = getchar() ));
  63.     ungetc(*p, stdin);
  64.     *p = '\0';
  65.     this.type = Classify_str();
  66.     return;
  67.   }
  68.   
  69.   if('*' == *p)
  70.   {
  71.     strcpy(this.string, "pointer to");
  72.     this.type = '*';
  73.     return;
  74.   }
  75.   this.string[1] = '\0';
  76.   this.type = *p;
  77.   return;
  78. }

  79. enum type_tag Classify_str(void)
  80. {
  81.   char *s = this.string;
  82.   if(STRCMP(s, ==, "const")){ strcpy(s, "read-only"); return Qualifier; }
  83.   if(STRCMP(s, ==, "volatile")) return Qualifier;
  84.   if(STRCMP(s, ==, "void")) return Type;
  85.   if(STRCMP(s, ==, "char")) return Type;
  86.   if(STRCMP(s, ==, "int")) return Type;
  87.   if(STRCMP(s, ==, "long")) return Type;
  88.   if(STRCMP(s, ==, "float")) return Type;
  89.   if(STRCMP(s, ==, "double")) return Type;
  90.   if(STRCMP(s, ==, "signed")) return Type;
  91.   if(STRCMP(s, ==, "unsigned")) return Type;
  92.   if(STRCMP(s, ==, "struct")) return Type;
  93.   if(STRCMP(s, ==, "union")) return Type;
  94.   if(STRCMP(s, ==, "enum")) return Type;
  95.   return Identifer;
  96. }

  97. void Deal_with_declarator(void)
  98. {
  99.   /*处理标识符之后可能存在的函数或数组*/
  100.   switch(this.type)
  101.   {
  102.     case '[': Deal_with_arrays(); break;
  103.     case '(': Deal_with_function_args(); break;
  104.     default: break;
  105.   }
  106.   
  107.   Deal_with_pointers();
  108.   
  109.   /*处理在读入标识符之前压入堆栈的符号*/
  110.   while(-1 < top)
  111.   {
  112.     if('(' == stack[top].type)
  113.     {
  114.       pop;
  115.       Gettoken();
  116.       Deal_with_declarator();
  117.     }
  118.     else
  119.       printf("%s ", pop.string);
  120.   }
  121.   return;
  122. }

  123. void Deal_with_arrays(void)
  124. {
  125.   while('[' == this.type)
  126.   {
  127.     printf("array ");
  128.     Gettoken();/*数字或']'*/
  129.     if(isdigit(this.string[0]))
  130.     {
  131.       printf("0..%d ", atoi(this.string)-1);
  132.       Gettoken();/*读取']'*/
  133.     }
  134.     Gettoken();/*读取']'之后的再一个标记*/
  135.     printf("of ");
  136.   }
  137.   return;
  138. }

  139. void Deal_with_function_args(void)
  140. {
  141.   while(')' != this.type)
  142.     Gettoken();
  143.   Gettoken();
  144.   printf("function returning ");
  145.   return;
  146. }

  147. void Deal_with_pointers(void)
  148. {
  149.   while('*' == stack[top].type)
  150.     printf("%s ", pop.string);
  151.   return;
  152. }

shellway@ubuntu:~/code$ gcc cdecl.c
shellway@ubuntu:~/code$ ./a.out
输入一个C语言声明,cdecl程序会把声明转化成通俗文字:
int *p
p is pointer to int
是否进行下一个声明的推断(y\n)?y
int (*pfun)(int,int)
pfun is pointer to function returning int
 
是否进行下一个声明的推断(y\n)?y
char * const *(*next)()
next is pointer to function returning pointer to read-only pointer to char
 
是否进行下一个声明的推断(y\n)?y
char *(*c[10])(int **p)
c is array 0..9 of pointer to function returning pointer to char
 
是否进行下一个声明的推断(y\n)?n
shellway@ubuntu:~/code$


阅读(2278) | 评论(0) | 转发(1) |
0

上一篇:没有了

下一篇:一道腾讯公司的面试题

给主人留下些什么吧!~~