分类: C/C++
2009-05-16 01:12:35
0515 学习笔记
第三章分析C语言的声明
一、结构
1) 结构就是一种把数据组合在一起的数据结构,结构的语法:
struct { 内容....}
结构的内容可以是任何其它数据声明,单个数据项目、数组、其它结构、指针等。
可以在结构的定义后面跟一些变量名,表示这些变量的类型就是这个结构,例如:
struct {内容..} plum,pear;
另外还可以在struct关键字后面加一个可选的”结构标签”:
struct fruit_tag{内容...} plum,pear;
因些通常所见的结构形式是:
struct 结构标签(可选){
类型1 标识符1;
类型2 标识符2;
....
}变量定义(可选);
2)最好把结构的声明和变量定义分开:
struct veg { int weight ,price_per_lb;}
struct veg onion,radish,turnip;
这样使代码看上去容易容易理解一些,而不是这些难以理解的代码:
struct veg{int weight,price_per_lb;} onion,radish,turnip;
3)结构和参数传递问题
参数在传递过程中首先尽可能地存放到寄存器中(追求速度)。但int型变量跟一个只包含int 型成员的变量s 在参数传递时的方式可能完全不同。一个int 型 参数一般会被传递到寄存器中,而结构参数则很可能被传递到堆栈中.
4)在结构中放置数组,这样就可以用赋值语句来拷贝整个数组,以传值调用的方式把它传递到数,或者把它作为函数的返回类型
struct s_tag { int a[100];}
struct s_tag orange,lime,lemon;
struct s_tag twofold(struct s_tag s){
int j;
for(j =0; j < 100 ;j++) s.a[j] *=2;
return s
}
main(){
int i;
for(i=0;i< 100 ;i++) lime.a[i] *=1;
lemon = twofold(lime);
orange = lemon;
}
二、关于typedef
1)typedef 是一种声明形式:它为一种类型引入新的名字,而不是为变量分配空间。在某些方面,typedef类似于宏文本替换(但也一个关键性的区别)
2)typedef 可以用于简洁的表示指向其他东西的指针。典型的例子是signal()原型的声明
void (*signal(int sig,void(*func)(int)))(int);
如果按照平常的方法去分析这个声明会比较吃力,现在用typedef代替一通用部分来帮助理解:
typedef void(*ptr_to_func)(int)//它表示ptr_to_func是一个函数指针,该函数接受一个int参数,返回值为void;
ptr_to_func signal(int,ptr_to_func);
//表示signal是一个函数,它接受两个参数,一个是int,另一个是ptr_to_func,返回值是ptr_to_func
3)使用typedef要注意的地方
可以把几个声明器放到一个声明中去。但这样会变得难以理解,如:
typedef int *ptr,(fun)(),arr[5];// *ptr 是指向int的指针,fun是指向返回值为int的函数指针类型;arr是长度为5的int 型数组
4)typedef 和宏替换的区别
1可以用其他类型的说明符对宏类型名称进行扩展,但typedef却不行:
#define peach int
Unsigned peach I;//没问题
Typedef int banana;
Unsigned banana I;//错误
2在连续几个变量的声明中,用typedef可以保证声明中所有类型的变量均为同一类型,而用#define则无法保证。如:
#define int_pty int *
Int_ptr chalk,cheese;
宏扩展后为 int * chalk,cheese//chalk的定义没错。但cheese则为一个int型变量,而不是期望的int *
5)关于C语言的名字空间
在同一个名字空间里,任何名字必须具有惟一性,但在不同的名字空间里可以相同,由于每个结构或者联合具有自己的名字空间,所以同一个名字可以出现在许多不同的结构内,如:
Struct foo{int foo;}foo;
三、分析C语言的复杂声明
C语言的语法力图使声明和使用想一致,所以情况比较复杂的情况下,容易让人混淆;
这里介绍一种“right-left”规则:
1)规则说明
0. 规则中符号
* 读作 “指向...的指针”
[] 读作 “...的数组”
() 读作 “返回...的函数”
1. 起始点
找到声明中的标识符(Identifier),它就是你分析的起始点,读作:“$(Identifier)是...”;
2. 右边
看你的标识符右边
a) 如果发现“()”,你将知道这是一个函数声明,这时你可以说“$(Identifier)是返回...的函数”;
b) 如果发现“[]”,你将知道这是一个数组声明,这时你可以说“$(Identifier)是...的数组”;
c) 继续向右,直到遇到右边声明结束或者遇到“)”,继续下面。
3. 左边
看你的标识符左边
a) 如果碰到的不是我们在0.中定义的符号,则直接说出它;否则按照0.中定义的符号含义说出。继续向左,直到遇到左边声明结束或“(”。
4. 重复2和3的步骤,直到声明分析完毕。
2) 例子详解
我们从简单到复杂,循序渐进。
[Example 1] int *p[];
1) 找到标识符:p,读作:“p是...”;
2) 向右看:发现一“[]”,然后遇到右边声明结尾,读作:“p是...的数组”;
3) 向左看:发现一“*”, 读作:“p是指向...的指针的数组”;
4) 继续向左看:没有发现0.中定义的符号,则分析结束,读作:“p是指向int类型的指针的数组”。
[Example 2] int *(*func())();
1) 找到标识符:func,读作:“func是...”;
2) 向右看:发现一“()”,然后遇到“)”,读作:“func是返回...的函数”;
3) 向左看:发现一“*”,然后遇到“(”,读作:“func是返回指向...的指针的函数”;
4) 向右看:发现一“()”,然后右边声明结束,读作:“func是返回指向返回...的函数的指针的函数”;
5) 向左看:发现一“*”,读作:“func是返回指向返回指向...的指针的函数的指针的函数”;
6) 向左看:没有发现.中定义的符号,则分析结束,读作:“func是返回指向返回指向int类型的指针的函数的指针的函数”。
3)常见不合法的声明符号组合
包括:
[]() - cannot have an array of functions
()() - cannot have a function that returns a function
()[] - cannot have a function that returns an array