这是一篇针对于C语言新手的文章,能够让你轻松的阅读C语言那恐怖的声明形式。
-------------------------------------------------------------------------------------
C语言声明的阅读方法:
找到声明的标识符,然后按照优先级规则进行读取
优先级: 1. 包含标识符的括号里的部分
2. 先看标识符(如果标识符包含在括号中则看括号)后面的后缀:
如果是小括号“()”则表示这是一个函数;
如果是方括号“[]”则表示这是一个数组。
3. 再看标识符(如果标识符包含在括号中则看括号)前面的前缀:
如果有星号“*”则表示这是一个指向……的指针。
注意:关键字const 和volatile 修饰的永远是它左边的东西,如果这两个关键字本身就在声明的最左边,那么它们就“只好”修饰右边的东西。
------------------------------------------------------------------------------------
现在让我们拿signal 函数的声明开个小刀 ;p
signal 的声明是:
- void (*signal(int signum,void (* handler)(int)))(int);
看起来有点惊心动魄?别怕,只要学会了上面的声明阅读方法再复杂的声明也轻松搞定 ;p
==================开始分析=================
找到声明的标识符signal,按照优先级规则读取。
先看包含标识符的括号里的部分:
先看后缀,signal 后面有小括号“()”,表示signal 是一个函数,括号里是一些参数。于是声明简化为:
再看前缀,signal 的左边是星号“*”,表示signal 的返回值是一个指针。
看标识符所在括号外面的部分:
先看后缀,后面是小括号“()”,则表示signal 返回的指针指向一个函数。
看这个小括号里面是关键字int, 表示signal 返回的指针指向的函数有一个int 型参数。
再看前缀,前面是关键字void ,则表示signal 返回的指针所指向的函数无返回值。
让我们把上面的分析综合起来:signal 是一个带参数的函数,返回一个指向以一个int 型变量做参数、无返回值的函数的指针。
好了,接着处理signal 的参数:
- int signum,void (* handler)(int)
先看第一个声明,找到标识符signum,只有一个用来修饰它的前缀int,则表示signum 是一个int 变量。
再看第二个声明,找到标识符 handler。
首先看标识符所在括号里的部分,只有一个用来修饰它的前缀星号“*”,表示handler 是一个指针。
再看标识符所在括号外面的后缀,发现小括号“()”,handler 指针指向一个函数。
看这个小括号“()”里面的部分,发现有一个关键字int, 则表示这个函数接受一个int 型参数。
接着看标识符所在括号外面的前缀,发现是关键字void,表示handler 指针指向的函数无返回值。
让我们把上面的分析综合起来:signum 是一个int 型变量,handler 是一个指向接受一个int 型参数、无返回值的函数的指针。
接着,我们把两部分的分析结果再做综合:
- void (*signal(int signum,void (* handler)(int)))(int);
的意思就是:signal 是一个函数。它的参数有两个:一个是int 型变量,另一个是一个函数指针,这个函数指针指向一个接受一个int 型参数、无返回值的函数。它的返回值是一个函数指针,指向的函数接受一个int 型参数、无返回值。
大功告成!
==================结束分析=================
下面给你个东西让你练练手 ;p
写一个函数指针,指向一个接受一个函数指针作为参数返回一个函数指针的函数。并用一个适当的main 函数版本来演示它的运行。
下面的代码是一种实现方法,不过你最好自己写完后再来看它 ;p- /* * * * * * * * * * * * * * * * * * * * *
-
* pfunc是一个函数指针,指向一个接受
-
* 一个函数指针做参数并返回一个函数指针的函数
-
*/
-
-
#include <stdio.h>
-
-
void (*func (void (*) (void))) (void);
-
void func2 (void);
-
-
int main
-
(void) {
-
-
void (*(*pfunc) (void (*) (void))) (void) = NULL;
-
void (*pfunc2) (void) = NULL;
-
void (*pfunc_tmp) (void) = NULL;
-
-
pfunc2 = func2;
-
pfunc = func;
-
pfunc_tmp = *(*pfunc) (pfunc2);
-
(*pfunc_tmp) ();
-
puts ("Press ENTER to quit.\n");
-
getchar ();
-
-
return 0;
-
}
-
-
void (*func (void (*pfunc) (void)))
-
(void) {
-
puts ("Though func.\n");
-
(*pfunc) ();
-
-
return pfunc;
-
}
-
-
void func2
-
(void) {
-
-
puts ("Though func2.\n");
-
-
return;
-
}
原本恐怖的C语言声明,现在看来是不是很简单呢 ? ;p
---------------补充点东西------------------
下面是09年从c专抄的,99%纯手工抄,不过机器分析很爽
- /*
-
cdecl程序,用于分析C语言的声明
-
*/
-
-
#include <stdio.h>
-
#include <ctype.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
#define STRCMP(a, R, b) (strcmp(a, b) R 0)
-
#define MAXTOKENS 100
-
#define MAXTOKENLEN 64
-
-
enum type_tag{ Identifer, Qualifier, Type };
-
-
struct token
-
{
-
char type;
-
char string[MAXTOKENLEN];
-
};
-
struct token stack[MAXTOKENS];
-
struct token this;
-
int top = -1;
-
-
#define pop stack[top--]
-
#define push(s) stack[++top] = s
-
-
void Read_to_first_identifer(void);
-
enum type_tag Classify_str(void); /*推断标识符的类型*/
-
void Gettoken(void);/*读取下一个标记到this*/
-
void Deal_with_declarator(void);
-
void Deal_with_arrays(void);
-
void Deal_with_function_args(void);
-
void Deal_with_pointers(void);
-
void Deal_wirh_declarator(void);
-
-
-
int main(void)
-
{
-
char next = 0;
-
printf("输入一个C语言声明,cdecl程序会把声明转化成通俗文字:\n");
-
do{
-
/*将标记压入堆栈,直至遇到标识符*/
-
Read_to_first_identifer();
-
Deal_with_declarator();
-
printf("\n是否进行下一个声明的推断(y\\n)?");
-
}while('Y' == toupper( next = getchar() ));
-
return 0;
-
}
-
-
void Read_to_first_identifer(void)
-
{
-
Gettoken();
-
while(Identifer != this.type)
-
{
-
push(this);
-
Gettoken();
-
}
-
printf("%s is ", this.string);
-
Gettoken();
-
return;
-
}
-
-
void Gettoken(void)
-
{
-
char *p = this.string;
-
-
while( ' ' == (*p = getchar()) );/*忽略空格*/
-
-
if(isalnum(*p))/*A~z,0~9*/
-
{
-
while(isalnum( *++p = getchar() ));
-
ungetc(*p, stdin);
-
*p = '\0';
-
this.type = Classify_str();
-
return;
-
}
-
-
if('*' == *p)
-
{
-
strcpy(this.string, "pointer to");
-
this.type = '*';
-
return;
-
}
-
this.string[1] = '\0';
-
this.type = *p;
-
return;
-
}
-
-
enum type_tag Classify_str(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, ==, "int")) return Type;
-
if(STRCMP(s, ==, "long")) return Type;
-
if(STRCMP(s, ==, "float")) return Type;
-
if(STRCMP(s, ==, "double")) return Type;
-
if(STRCMP(s, ==, "signed")) return Type;
-
if(STRCMP(s, ==, "unsigned")) return Type;
-
if(STRCMP(s, ==, "struct")) return Type;
-
if(STRCMP(s, ==, "union")) return Type;
-
if(STRCMP(s, ==, "enum")) return Type;
-
return Identifer;
-
}
-
-
void Deal_with_declarator(void)
-
{
-
/*处理标识符之后可能存在的函数或数组*/
-
switch(this.type)
-
{
-
case '[': Deal_with_arrays(); break;
-
case '(': Deal_with_function_args(); break;
-
default: break;
-
}
-
-
Deal_with_pointers();
-
-
/*处理在读入标识符之前压入堆栈的符号*/
-
while(-1 < top)
-
{
-
if('(' == stack[top].type)
-
{
-
pop;
-
Gettoken();
-
Deal_with_declarator();
-
}
-
else
-
printf("%s ", pop.string);
-
}
-
return;
-
}
-
-
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 ");
-
}
-
return;
-
}
-
-
void Deal_with_function_args(void)
-
{
-
while(')' != this.type)
-
Gettoken();
-
Gettoken();
-
printf("function returning ");
-
return;
-
}
-
-
void Deal_with_pointers(void)
-
{
-
while('*' == stack[top].type)
-
printf("%s ", pop.string);
-
return;
-
}
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$
阅读(2363) | 评论(0) | 转发(1) |