第三章 分析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      轻松一下——驱动物理实体的软件

《C专家编程》读书笔记3相关推荐

  1. 《人人都是产品经理》第四章读书笔记及读后感作文2400字

    <人人都是产品经理>第四章读书笔记及读后感作文2400字: 最近一直在忙别的学习,以至于好久没有更新公众号了,也好久没有写读书笔记了.<人人都是产品经理>这本书其实早在一个月前 ...

  2. 《营销5.0后互联网时代的企业战略营销》读书笔记

    文章目录 前言 营销 1.0 到营销 5.0 的发展路径 CIDR 模型 小结 前言 怀着对"营销"继续探索的心情,今年3月份完成了<营销5.0>的阅读,读本书的初衷是 ...

  3. 《互联网+:小米案例版》的读书笔记

    读书笔记 摘自<互联网+:小米案例版刘润> 互联网+:小米案例版刘润 序篇 创业方法论之变 雷军反复强调的"顺势而为",以及"站对了风口,猪都能飞起来&quo ...

  4. 互联网产品经理(PM)的工作内容和职责

    互联网产品经理的角色和职责在不同的互联网公司会存在一定差异,但是一些关键职责是任何一个产品经理都应承担的,下面我们按照产品阶段将互联网产品经理的职责整理为一下五个方面: 一.市场调研及用户研究 即研究 ...

  5. 一组漫画告诉你,互联网产品经理是什么概念

    一.什么是产品经理 1. 1 什么是产品 产品是满足用户需求,被使用和消费的任何东西.包括有形的物品和无形的服务. 在了解产品经理之前,先来了解一下什么是产品.产品充斥在我们生活中的方方面面.鞋子.手 ...

  6. 《修炼之道:互联网产品从设计到运营》荣获“2012最受读者喜爱的IT人文类图书奖”!

    <修炼之道:互联网产品从设计到运营>获得51CTO 主办的"2012最受读者喜爱的IT人文类图书奖",http://t.cn/zjjaXNo! 如何在寸土寸金的首页上使 ...

  7. 互联网产品的交互设计方法

    目前交互设计在互联网产品中的应用状况 "交互设计可以提高产品可用性."在国内的互联网行业中,建立在这个认识基础上,交互设计得到了普遍的接受."产品设计开始的时候应该先交互 ...

  8. 为什么互联网能创造商业奇迹——我的互联网产品观

    作者   网易·崔晓宇 互联网的出现突破了时间.地域的局限性,它使信息可以更快的速度传播到更广的范围,从时间和空间维度上看形成了真正的信息流.高效的流动让信息与生俱来的价值属性得以提升.我认为信息已经 ...

  9. 互联网产品的定义及分类

    产品类型 产品是指能够提供给市场,被人们使用和消费,并能满足人们某种需求的任何东西,包括有形的物品.无形的服务.组织.观念或它们的组合.产品一般可以分为三个层次,即核心产品.形式产品.延伸产品.核心产 ...

  10. 怎么做好互联网产品运营?

    怎么做好互联网产品运营? 一.什么是运营? 从广义的角度上说,一切围绕着网站产品进行的人工干预都叫运营.所以某种程度上,我认为互联网产品公司只有3个业务部门:产品,技术,运营. 产品运营这个概念就=运 ...

最新文章

  1. redis集群之REDIS CLUSTER
  2. ASP.NET MVC的生命周期与网址路由
  3. 利用Python编写网络爬虫下载文章
  4. 【ROS问题】rqt_plot运行报错
  5. 数论一之定理证明——裴蜀/威尔逊/费马/扩展欧几里得/[扩展]欧拉/[扩展]中国剩余定理,欧拉函数,逆元,剩余系,筛法
  6. jquery 样式获取设置值_jQuery获取样式中的背景颜色属性值/颜色值
  7. 定义整型数组_C语言基础-数组怎么用
  8. -9 逆序输出一个整数的各位数字_逆序对个数(归并排序)
  9. 元素上下层叠关系总结
  10. Debian/Ubuntu系统下,apt-get update 、apt-get upgrade 、apt-get dist-upgrade 命令之间的区别
  11. 保存多序列tiff文件_干货技巧!如何使你保存的Phtoshop文件容量更小?
  12. SpringBoot框架中解决日期展示问题
  13. VMWare安装苹果Mac OS X
  14. ansys linux 安装教程pdf,Deepin linux安装Ansys13详细教程.pdf
  15. c语言同构数怎么表示,C语言求同构数
  16. 青少年python编程入门范例_青少年Python编程入门—图解Python
  17. macOS制作Linux启动U盘,如何在Mac OS下用ISO包制作启动U盘
  18. php微信支付的分账,微信支付分账,就是这么简单!
  19. amdr7-4700linux,Yoga14s 2021 ARH R7 4800H 安装Arch Linux
  20. 红烧牛肚的做法大全 红烧牛肚怎么做好吃

热门文章

  1. 采集google搜索引擎的10个经典方法
  2. Google advertiser api开发概述——批量处理
  3. 视频处理——去交错原理
  4. Jmeter脚本制作与调优脚本参数化
  5. php鲜花销售理论意义,鲜花销售系统(论文+源代码)论文有用
  6. 简化STM32编程,eBox归来,助一臂之力
  7. 从户外广告“全面轰炸”看凡客的品牌营销理念
  8. 【蓝桥真题】三羊献瑞,祥瑞生辉+三羊献瑞=三羊生瑞气(暴力破解)
  9. 什么是GML?GML例子
  10. 6.堆(动态内存 heap)的初始化和使用