《C专家编程》读书笔记3

 第三章 分析C语言的声明

   

3.1    只有编译器才会喜欢的语法

 

        char (*j) [20];/*j是一个指向数组的指针,数组内有20个char元素*/

        j = (char (*)[20]) malloc(20);

        如果把星号两边看上去明显多余的括号拿掉,代码会变成非法的。

 

        涉及指针和const的声明可能会出现几种不同的顺序:

        const int *grape;

        int const *grape;

        int * constgrape_jelly;

        在最后一种情况下,指针是只读的,而在另外两种情况下,指针所指向的对象是只读的。当对象和指针都是只读的,下面两种声明方法能做到这一点:

        const int * const grape_jam;

        int const * const grape_jam;

 

3.2       声明是如何形成的

 

        声明器就是标识符以及与它组合在一起的任何指针、函数括号、数组下标等

       

       

 

3.2.1  关于结构

 

        结构的通常形式是:

        struct 结构标签(可选){

             类型1 标识符1;

        类型2 标识符2;

        ……

        类型N 标识符N;

        }变量定义(可选);

        struct vegonion, radish, turnip;

 

        有些C语言书记声称“在调用函数时,参数按照从右到左的次序压到堆栈里。”这种说法过于简单。参数在传递时首先尽可能地存放到寄存器中(追求速度)。注意,int型变量i跟只包含一个int型成员的结构变量s在参数传递时的方式可能完全不同。一个int型参数一般会被传递到寄存器中,而结构参数则很可能被传递到堆栈中。

 

        在结构中放置数组,如

        struct s_tag {int a[100]; };

        现在,可以把数组当做第一等级的类型,用赋值语句拷贝整个数组,以传值调用的方式把它传递到函数,或者把它作为函数的返回类型。

        在典型情况下,并不会频繁地堆整个数组进行赋值操作。但是如果需要这样做,可以通过把它放入结构中来实现。

 

3.2.2  关于联合

 

        联合的外表与结构相似,但在内存布局上存在关键性的区别。在结构中,每个成员依次存储,而在联合中,所有的成员都从偏移地址零开始存储。这样,每个成员的位置都重叠在一起:在某一时刻,只有一个成员真正存储于该地址。

        联合既有一些优点,也有一些缺点。它的缺点就是那些所谓的优点其实并不怎么出色。

 

        union 可选的标签 {

             类型1 标识符1;

        类型2 标识符2;

        ……

        类型N 标识符N;

        }可选的变量定义;

 

        联合一般是作为大型结构的一部分存在的。

        联合一般被用来节省空间,因为有些数据项是不可能同时存在的。例如,如果我们想要存储一些关于动物种类的信息,首先想到的方法可能是:

        sttuct creature{

            char has_backbone;

            char has_fur;

            short num_of_legs_in_excess_of_4;

        };

        但是,我们知道,所有的动物要么是脊椎动物,要么是无脊椎动物。进而,我们还知道,只有脊椎动物才可能有皮毛,只有无脊椎动物才可能有多于4条的腿。没有一种动物既有毛皮又有超过4条的腿。这样,可以通过把两个互相排斥的字段存储于一个联合中来节省空间:

        union secondary_characteristics{

            char has_fur;

            short num_of_legs_in_excess_of_4;

        };

        sttuct creature{

            char has_backbone;

            union secondary_characteristics;

        };

 

        合也可以把同一个数据解释成两种不同的东西。

        union bits32_tag{

             int whole;    /*一个32位的值*/

             struct { char c0, c1, c2,c3; } byte;   /*4个8位的字节*/

        }value;

        这个联合允许提取整个32位值(作为int),也可以提取单独的字节字段如value.byte.c0等。

 

3.2.3    关于枚举

 

        enum 可选标签 {内容……}可选变量定义;

 

3.3      优先级规则

 

        C语言声明的优先级规则

        1.      声明从它的名字开始读取,然后按照优先级顺序依次读取

        2.      优先级从高到底依次是:

                2.1       声明中北括号括起来的部分

                2.2       后缀操作符:括号()表示这是一个函数,而方括号表示这是一个数组。

                2.3        前缀操作符:星号*表示“指向…的指针”。

        3.      如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等)它作用于类型说明符。在其他情况下,const和(或)volatile关键字作用于紧邻的指针星号。

 

        char * const *(*next)();

        首先,看变量名“next”,并注意到它直接被括号所括住。

        所以先把括号里的东西看做是一个整体,得出“next是一个指向…的指针”,然后考虑括号外面的东西,在星号和括号后缀之间作出选择

        右边的函数括号优先级较高,所以得出“next是一个函数指针,指向一个返回…的函数”

        然后,处理前缀“*”,得出指针所指向的内容

        最后,把“char* const”解释为指向字符的常量指针

        “next是一个指针,指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针”

 

3.4   通过图表分析C语言的声明

 

        char *(* c[10])(int **p);

        c是一个数组,它的元素类型是函数指针,其所指向的函数的返回值是一个指向char的指针

 

3.5    typedef可以成为朋友

 

        void ( *signal (int sig, void (*func)(int) ) )(int)

        void ( *signal (                   ) )(int)

        signal是一个函数,它返回一个函数指针,所指向的函数接受一个int参数并返回void。其中一个恐怖的参数是其本身。

        void (*func)(int);

        用typedef来“代表”通用部分,从而进行简化。

        typedef void (*ptr_to_func)(int);

        ptr_to_func signal(int, ptr_to_func);

 

3.6      typedef int x[10]和#define x int[10]的区别

 

        typedef和宏的区别体现在两个方面:

        首先,可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。

        #define peach int

        unsigned peach i;/*没问题*/

        typedef int banana;

        unsigned banana i; /*错误!非法*/

        其次,在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一种类型,而用#define定义的类型则无法保证。如下所示:

        #define int_ptr int *

        int_ptr chalk, cheese;

        经过宏扩展,第二行变为:

        int * chalk, cheese;

 

3.7      typedef struct foo{… foo;}的含义

 

        typedef struct my_tag { int i; } my_type;

        struct my_tag variable_1;

        my_type variable_2;/*此处已经不需要struct*/

        这个typedef声明引入了my_type这个名字作为“struct my_tag { int i; }”的简写形式。

 

        typedef struct fruit { int weight, price_per_lb;} fruit;

               struct veg{ int weight,price_per_lb;} veg;

        struct fruit mandarin;/* 使用结构标签”fruit” */

        fruit mandarin;/* 使用结构类型”fruit” */

        struct veg potato;

        如果试图使用veg potato;将是一个错误。

 

        不要为了方便起见对结构使用typedef。

        这样做的唯一好处是能使你不必书写“struct”关键字。

        typedef应该用在:

        数组、结构、指针以及函数的组合类型。

        可移植类型。

        也可以为后面的强制类型转换提供一个简单的名字。

 

        如果搞不清楚哪个名字是结构标签,就为它取一个以“_tag”结尾的名字。

 

3.8      理解所有分析过程的代码段

3.9      轻松一下——驱动物理实体的软件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值