C语言之声明
1.声明与定义
声明语法
说明符(说明类型或修改缺省属性) 声明表达式列表
- 说明符
- 类型说明:int, float
- 存储属性:static,auto
- 类型限定:const, volatile
声明 VS 定义
- 说明类型:取值范围和合法操作
- 定义:分配存储空间
2.初始化
显式初始化
- 静态变量(含全局变量):使用常量表达式 初始化一次
- 自动变量:每次执行时使用赋值语句初始化
非显式初始化
- 静态变量(含全局变量):编译时初始化,缺省值为0
- 自动变量:运行时初始化,缺省为无效值
3.复杂声明与typedef
复杂声明
左右法则:从最里面的圆括号(未定义的标识符)开始,先看其右边,再看其左边,遇到括号时调转方向。一旦解析完括号的内容即可跳出圆括号,重复该过程直到解析完毕。
C
int *(*(*f)(int))[10];
// (*f) f是一个指针
// (*f1(int)) f1是一个函数指针,所指向的函数返回值是一个指针,参数是(int)
// int *f2[10] f2是一个数组指针,指向数组 int * a[10]
// 综上,f是一个函数指针,指向函数参数为(int), 返回值为指向 int *a[10]的数组指针,其所指向的数组元素类型为 int*
// pointer to function returning pointer to array[10] of pointer to int
char (*(*x())[])();
// *x(), x是一个函数,返回值类型是一个指针
// *(x1)[], x1是一个指针数组,元素类型是指针
// char x2(), x2是一个函数,返回值类型为char
// 综上,x是一个函数,返回值类型是一个指针数组,其数组元素类型是返回值类型为char的函数的指针
// function returning pointer to array[] of pointer to function returning char
char (*(*x[3])())[5];
// *x[3], x是一个数组,元素类型是指针
// *x1(), x1是一个函数,返回值是指针
// char x2[5], x2是数组,元素类型是char
// 综上,x是一个数组,元素类型是函数指针,该函数返回值类型是数组指针,指向元素类型为char的数组
// array[3] of pointer to function returning pointer to array[5] of char
Unix 系统的 cdecl 程序实现了声明的解析,可参考 comp.sources.unix.newsgroup
typedef
语法和声明类似,将标识符作为类型的别名
1. 让代码更加清晰简洁
-
定义结构体,联合,枚举等变量
Ctypedef struct student { char name[]; int score; } T_Stu, *PT_Stu; T_Stu tStu1 = {"Bob", 78}; PT_Stu ptStu1 = &tStu1; typedef enum color { red, white, block, } colot_t; color_t color1 = red;
-
简化复杂声明
C// int *(*array[10])(int *p); typedef int *(func_ptr)(int *p); func_prt array[10];
2. 增加代码的可移植性
int 类型在不同的编译器和平台下所分配的存储字节不同,使用自定义的数据类型而不是内置类型来增强可移植性
C
#ifdef PIC_16
typedef unsigned long u32 // 2 bytes for int, 4 bytes for long
#else
typedef unsigned int u32 // 4 bytes for both int and long in PIC_32
#endif
typedef 的适用情景
- 创建一个数据类型的别名
- 跨平台的指定长度的类型, u32
- 与操作系统,BSP,网络字节相关的数据类型,如size_t, pid_t等
- 不透明的数据类型,需要隐藏数据结构实现细节,只开放函数接口
避免滥用typedef: 参考 Linux Kernel Documennt的CodingStyle
4.辨析
-
数组与指针参数
Cint fun(char *str); int func(char str[]); // 二者仅在当前声明上下文一致
-
数组和指针初始化
Cchar *p = "hello"; char a[] = "hello"; // 特殊形式,等价于 char a[] = {'h', 'e', 'l', 'l', 'o', '\0'};
-
声明与定义
Cint a; // 变量的声明和定义 extern int b; // 变量的声明 void f1(void){}; // 函数的声明和定义 void f2(void); // 函数的声明
-
typedef VS #define
typedef等价于存储类关键字,宏定义只是字符串替换
- typedef 不支持继续使用static等存储类关键字
- 宏定义不支持指针声明
- typedef 具有作用域,宏定义在预处理阶段进行全局替换
C#define int *POINTER_TO_INT POINTER_TO_INT a, b, c; // b, c 无法被声明为指针类型 // 与const关键字 typedef char* PTCHAR1; #define PTCHAR2 char*; const PTCHAR1 p1; // PTCHAR1作为类型,可与consat调换位置,const修饰p1,指针常量 const PTCHAR2 p2; // 等价于 const char* p2; char可与const调换位置,const修饰(*p2),常量指针
//TODO Linux 内核中的声明,学习Linux源码时
5.参考
- 《C和指针》
- 3.2 声明
- 3.3 typedef
- 13.2 高级声明
- 《嵌入式C语言的自我修养》
- 7.5 typedef
- 7.8.2 复杂声明
- 9.4 头文件的深度解析
- 《C程序设计语言》
- 2.4 声明
- 4.9 初始化
- 5.12 复杂声明
- 6.7 类型定义(typedef)
- 《C专家编程》
- 3 C语言的声明
- 4.3 声明与定义