C语言声明的优先级规则
通过上述规则分析下面C语言声明:
1
2
3
|
char * const *(*next)();
//next是一个指针,它指向一个函数,该函数返回一个另一个指针,
//该指针指向一个类型为char 类型的常量指针
|
typedef作用
在C语言中,typedef关键字用于定义新的数据类型别名。它的作用有以下几个方面:
-
简化复杂的数据类型名称:typedef可以用来为复杂的数据类型定义一个简单的别名,使得代码更易读、易懂。例如,可以使用typedef为指针类型定义一个简单的别名,并没有创建新的类型,使得代码中使用该指针类型的地方更加清晰明了。
-
提高代码的可维护性:通过typedef定义别名,可以使得代码中使用的数据类型更加具有可读性和可维护性。如果需要修改某个数据类型的名称,只需要修改typedef的定义,而不需要修改所有使用该数据类型的地方。
-
提高代码的可移植性:通过typedef定义别名,可以使得代码更加具有可移植性。在不同的平台或编译器上,可能存在不同的数据类型名称,使用typedef定义别名可以屏蔽这种差异,使得代码在不同的平台上都能够正常编译和运行。
-
增加代码的可读性:通过typedef定义别名,可以使得代码更加易读。通过为数据类型定义一个有意义的别名,可以增加代码的可读性,使得代码更加易于理解和维护。
典型的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
//signal()原型的声明,signal是一个函数,它返回一个函数指针,
//这个函数指针指向的函数接受一个int参数并返回void。
void (*signal(int sig, void (*func)(int)))(int)
//可通过typedef做如下改变
typedef void (*sighandler_t)(int); //可以使用sighandler_t直接代替void (*)(int)
sighandler_t signal(int signum, sighandler_t handler);
//定义结构体别名:
typedef struct {
int x;
int y;
} Point;
// 可以使用Point直接代替struct Point
Point p;
p.x = 10;
p.y = 20;
定义指针类型别名:
typedef int* IntPtr;
// 可以使用IntPtr直接代替int*
IntPtr p;
int x = 10;
p = &x;
//定义函数指针类型别名:
typedef int (*MathFunc)(int, int);
// 可以使用MathFunc直接代替int (*)(int, int)
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
MathFunc func;
func = add;
int result = func(5, 3); // 调用add函数,结果为8
func = subtract;
result = func(5, 3); // 调用subtract函数,结果为2
|
C语言存在多种名字空间:
在同一个名字空间里,任何名字必须具有唯一性,但在不同的名字空间里可以存在相同的名字。由于每个结构或者联合具有自己的名字空间,所以同一个名字可以出现在许多不同的结构内。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
typdedef struct my_tag{int i;}mytype;
struct my_tag var1;
mytype var2;
//这个typedef声明引入了mytype这个名字作为"struct my_tag{int i;}"的简写方式。
//但它同时引入了结构标签my_tag,在他前面加个关键字struct可以表示同样的意思。
typedef struct fruit {int weight;}fruit; //语句1
struct veg{int weight;}veg; //语句2
//语句1声明了结构标签fruit和typedef声明的结构类型fruit;实际效果如下
struct fruit mandarin;
fruit mandarin;
//语句2声明了结构标签veg和变量veg,只有结构标签能够在以后的声明中使用,如
struct veg potato;
//如果试图使用veg cabbage这样的声明,将是一个错误。这有点类似下面的写法:
int i;
i j;
|
typedef、宏定义替换之间的区别
可以把typedef看成是一种“封装”类型—-在声明之后不能再往里面增加别的东西。它和宏的区别体现在两个方面
- 可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。
1
2
3
4
5
|
#define peach int
unsigned peach i; //没问题
typedef int peach;
unsigned peach i; //语法错误
|
- 连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一种类型,而用#define定义的类型无法保证
1
2
3
4
5
6
7
8
9
10
|
#define int_ptr int *
int_ptr chalk, cheese;
//经过宏扩展
int *chalk, cheese;
chalk是一个指针,cheese是一个整型。
typedef int* int_ptr;
int_ptr chalk,cheese;
chalk,cheese都为整型指针
|
枚举类型
enum sizes { small = 7, medium, large = 10, humungous};
缺省情况下,整型值是从零开始。如果对列表中的某个标识符进行了赋值,那么紧接其后的那个标识符的值就比所赋的值大1,然后类推
枚举中的成员可以当做宏一样直接使用,相比宏定义枚举具有一个优点:#define定义的名字一般在编译时被丢弃,而枚举名字则通常一直在调试器中可见,可以在调试代码时使用它们。