《C专家编程》笔记(三)——分析C语言的声明
1. 几个C语言声明的分析
char (*j)[20];
j = (char(*)[20]) malloc(20); // j是指向数组的指针
const int * grape;
int const * grape;
int * const grape_jelly;
const int * const grape_jam;
int const * const grape_jam;
char * const * (*next)(); // next是指向函数的指针,这个函数不接收参数,它的返回值是指向char * const的指针。
2. 一些非法声明及合法声明的限制条件
非法:函数的返回值不能是一个函数;函数的返回值不能是一个数组;数组里面不能有函数。
合法:函数的返回值允许是一个函数指针;函数的返回值允许是一个指向数组的指针;数组里面允许有函数指针;数组里面允许有其他数组。
3. 声明的优先级规则
A. 声明从它的名字开始读取,然后按照优先级顺序依次读取。
B. 优先级从高到低依次是:
B.1 声明中被括号括起来的那部分
B.2 后缀操作符:
括号( )表示这是一个函数,而
方括号[]表示这是一个数组。
B.3 前缀操作符:星号*表示“指向……的指针”。
C. 如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符。在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。
4. 使用typedef来将声明简化
在ANSI C标准中,signal()的声明是void ( *signal( int sig, void( *func )( int ) ) ) ( int );
根据规则B.2,我们知道signal是个函数(这不同于上面的next,next是直接被括号括住),这个函数的参数是int sig, void(*func)(int),返回值是void (*)(int)。
我们使用typedef来提取signal声明中的通用部分,简化这个声明。
typedef void(*ptr_to_func) (int);
则signal的声明成了:ptr_to_func signal(int sig, ptr_to_func);
5. typedef int x[10]和#define x int[10]的区别
typedef int x[10]将x设为含有10个元素的整型数组的类型。#define x int[10]只是简单地进行文本替换。
typedef int x[10];
x arr1, arr2, arr3; // 合法
#define x int[10];
x arr1, arr2, arr3; // 非法
#define peach int
unsigned peach i; // 合法
typedef int banana;
unsigned banana i; // 非法
#define int_ptr int *
int_ptr chalk, cheese; // chalk为int*, cheese为int
typedef int * int_ptr;
int_ptr chalk, cheese; // chalk和cheese均为int*
6. 几条使用typedef的建议
不要为了方便起见对结构使用typedef。这样的唯一好处是可以节省书写struct,然而struct关键字可以向你提示这一信息。
typedef应该用在:数组、结构、指针以及函数的组合类型;可移植类型;为后面的强制类型转换提供一个简单的名字。