第三章 分析C语言的声明
(1)const
const int * grape; //指针所指向的对象是只读的
int const * grape; //指针所指向的对象是只读的
int * const grape_jelly; //指针是只读的
(2)在合法的声明中存在限制条件
不可以像下面这样做:
函数的返回值不能是一个函数,也不能是一个数组;
数组里面不能有函数。
但像下面这样则是合法的:
函数的返回值允许时一个函数指针,也允许时一个指向数组的指针;
数组里面允许有函数指针,也允许有其他数组。
(3)结构中允许存在位段、无名字段以及字对齐所需的填充字段,这些都是通过在字段的声明后面加一个冒号以及一个表示字段位长的整数来实现的。
struct pid_tag {
unsigned int inactive : 1;
unsigned int : 1; /*1个位的填充*/
unsigned int refcount : 6;
unsigned int : 0; /*填充到下一个字边界*/
short pid_id;
};
位段的类型必须是int, unsigned int 或signed int(或加上限定符),至于int位段的值可不可以取负值则取决于编译器。
(4)参数在传递时首先应尽可能地存放到寄存器中(追求速度)。
(5)在结构中,每个成员依次存储,而在联合中,所有的成员都从偏移地址零开始存储。这样,每个成员的位置都重叠在一起:在某一时刻,只有一个成员真正存储于该地址。
(6)枚举有点:#define定义的名字一般在编译时被丢弃,而枚举名字则通常一直都在调试器中可见,可以再调试代码时使用它们。
(7)C语言声明的优先级规则:
A 声明从它的名字开始读取,然后按照优先级顺序依次读取。
B 优先级从高到低依次是:
B.1 声明中被括号括起来的那部分
B.2 后缀操作符:
括号( )表示这是一个函数,而方括号[]表示着是一个数组。
B.3 前缀操作符:星号*表示“指向...的指针”。
C 如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符。在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
(8)typedef
a. typedef为一种类型引入新的名字,而不是为变量分配空间。
b. 普通的声明表示“这个名字是一个指定类型的变量”,而typedef关键字并不是创建一个变量,而是宣称“这个名字是指定类型的同义词”。
c. 提示:不要在一个typedef中放入几个声明器;千万不要把typedef嵌到声明的中间部分。
d. typedef为数据类型创建别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。
e. typedef与宏的区别:
首先,可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。如:
#define peach int
unsigned peach i; /*OK*/
typedef int banana;
unsigned banana i; /*非法,错误*/
其次,在连续的几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一种类型,而用#define定义的类型则无法保证。如:
#define int_ptr int *
int_ptr chalk, cheese;
扩展为int * chalk, cheese; 这使得chalk是一个指向int的指针,而cheese则是一个int。相反,下面的代码中:
typedef char * char_ptr;
char_ptr Bentley, Rolls_Royce;
Bentley和Rolls_Royce的类型依然相同,虽然前面的类型名变了,但它们的类型相同,都是指向char的指针。
f. 不要为了方便起见对结构体使用typedef,这样的唯一好处是不必书写“struct” 关键字,但该关键字可以提示一些信息,使代码更为清晰。
typedef应该用在:
数组、结构、指针以及函数的组合类型;
可移植类型。