《C专家编程》:语言类型的声明(三)

来源:互联网 发布:pycharm使用教程 mac 编辑:程序博客网 时间:2024/04/28 07:53

        C语言在声明各种类型的变量,函数等的时候包含一个十分重要的东西,那就是声明器(declarator)-它是所有声明的核心。简单的说,声明器就是标识符以及与它组合在一起的任何指针、函数括号、数组下表等。有些事合法但是有些是非法的:

        例如fool()(),或者foo()[]这都是非法的。

        但是const  int* (*p(int **p))(char *str,float p);这样的都是合法的。

一、结构-struct
         结构就是把一些数据项结合在一起的数据结构。其他编程语言 把它称为记录(record)。进行组合的通常方法就是把需要组合的东西放在花括号里面。
struct fruit{//各种变量}fruit1,fruit2; //fruit1和fruit2都是同一种类型;
         在C语言中,struct关键字不能省略;
         另外有两个跟结构有关的参数传递问题。有些C语言书籍称:“在调用函数时,参数是按照从右到左压入栈里。”这种说法太简单了!事实上,参数在传递的过程中,应尽可能的放入寄存器中(追求速度)。注意int型变量i跟只包含一个int型成员的结构变量s在参数传递的过程中可能完全不同。一个int类型的参数一般会将其放入寄存器中,而结构参数很可能被传入到堆栈中。
二、联合-union

         联合在其他语言中被称为变体记录(variant record)。它的外表与结构体类似,但在内存的布局上有着关键性的区别。在结构中每个成员一次存储,而在联合中,所有的成员都从偏移地址零开始存储。这样,每个成员的位置重叠在一起:某一时刻,只有一个成员真正存储于该地址

         联合一般被用来节省空间,因为有些数据项是不可能同时出现的,如果同时存储他们显的有些浪费空间。就好比要记录一块显示屏上某一时刻的数据信息:出现的数字有可能是int,float,也有可能是字符串,有可能是图片等等;但是某一个时刻就只能显示其中一个,我们也只需要某一时刻的数据,这时候我们就可以用union数据结构,这样不仅能存储所有的数据类型,还节省了大量的空间。

例如下面的程序:
union{   int num;   struct{char a,b,c,d}byte;}value;
 这样我们可以轻易地取得单独字节字段,如:value.byte.a。不需要额外的空间赋值或者强制类型转换。
三、枚举-enum
         枚举通过一种简单的途径,把一串名字与一串整形数值联系在一起。但是在C语言中,很少只有枚举能完成而#define不能完成,所以大多数早期的K&RC编译器中,都省掉了枚举。不过由于枚举在大说书语言宏也存在,所以C语言最终也是实现了它。
enum number{small=5,medium,large=10,humungous};//类似于定义了一堆宏;
    缺省情况下,整形值从零开始。赋值后,后面的以此+1;
    注意:#define和枚举还是有一个很大的区别,这也是枚举的优点。#define定义的名字一般在编译器时被丢弃,而枚举名字则通常一直在调试器中可见,可以在调试代码的时候看见,这方变了软件设计者们find bug。
       这也是在Effective C++中条款一:尽量使用inline和const代替#define的主要原因之一。
四、C语言声明的优先级原则:
     理解C语言的优先级可以轻松帮我们搞定C语言声明:
      例如在开篇提到的合法的申明:const int* (*p(int **p))(char *str,float p);
      它到底是什么意思呢?这就需要我们熟悉C语言的优先级:
 优先级法则:
 声明从它的名字开始读起,然后按照优先级顺序一次读取。
 优先级从高到底依次是:
(1)声明中被括号括起来的部分;
(2)后缀操作符:
        括号()表示这是一个函数;
方括号[]表示这是一个数组;
(3)前缀操作符:*表示“指向...的指针”;
       那么开篇的声明解释为:p是一个函数,函数有一个参数,该参数是一个指向指针的指针,该指针指向int类型;返回值是一个指针,是一个指向函数的指针,该函数有两个参数,一个是指向char类型的指针,一个是float类型的值;该函数返回值是一个指针,是一个指向只读的整型数据的指针。
五、typedef
         typedef是一种有趣的声明,它为一种类型引入新的名字,而不为变量分配内存空间。typedef类似于宏文本替换,因为它并没有引入新的类型。而是为现有的类型取一个新的名字。
     一般情况下,typedef用于简洁的表示指向其他东西的指针。
还是以开篇提到的声明为例:
const int* (*p(int **p))(char *str,float p);
这个声明看起来不那么友好,那么怎样使其看起来比较简洁呢?这个时候typedef就派上了用场。
typedef const int *(*pFun)(char *str,float p);

那么此时该声明可以简化为:

pFun p(int **p);

我们还可把上述的声明继续复杂化:
const int* (*p(int **p,void (*pFun1)(int a)))(char *str,float p);
看这个声明,其实也没什么,在复杂也不要怕,一层层的拨开它的真面目,其实真的没什么?
看我们定义两个类型:
typedef void (*pFunt1)(int );typedef const int *(*pFunt2)(char *str,float p);那么上式简化为:pFunt2 p(int **p,pFunt1 );
这样一看就十分明了,一个函数带两个参数,就是这么简单,没有什么大不了的地方!
前面说了typedef和#define类似,但是它们还是会有关键性的区别:
(1)#define定义的宏可以用其他类型进行扩展,但是typedef不行:
 例如:
#define INT int unsigned INT a;//OK,这里没有问题; //但是: typedef int INT; unsigned INT a;//ERROR,这是非法的;
 (2)typedef定义的类型能够保证声明中所有的变量均为同一类型,但是#define不行:
 例如:
typedef int* INTeger;INTeger a,b;//这里a,b都是int *类型的;//但是:#define INTeger int*INTeger a,b;//这里a是int*,但是b是int类型的;
     注:typedef应该使用在数组、结构、指针以及函数的组合类型。

2 0
原创粉丝点击