玩儿转C语言:声明和定义(1)
C语言的设计哲学:对象的声明形式和它的使用形式尽可能相似。例如: 指针数组定义为int *p[4],使用指针指向的int数据时写成*p[i],他们形式相似。优点是:各种操作符的优先级在“声明”和“使用”时是一样的;缺点是:操作符的优先级太多相当复杂,无法以习惯的方式从左到右阅读一个声明来确定数据。
例如:
int * P[5] :指针数组(数据元素全为指针的数组),本质是一个数组,内容是指向int类型数据的指针(地址)。
int (*P) [5] :数组指针(指向数组的指针),本质是一个指针,指针的数据是一个由5个int数据组成的数组的首地址。
如果想要区分这两个声明,就必须了解*和[]的优先级,默认情况下*优先级低于[]。对于int * P[5],先看P[5]确定这是一个数组,再看int * 确定数组的内容是指向int的指针;对于int (*P) [5],由于括号的存在,先看括号里边的 *,确定这是一个指针P,再看int [5]确定指针指向的是一个由5个int数据组成的数组。C语言的优先级有15级之多,所以分析声明类型是相当恐怖的。
const int * vol_ptr和int const * vol_ptr : 表示指针指向的数据是只读的,辅助记忆:const在*左边离数据比较近,故作用于数据上。
int * const vol_ptr :表示指针本身是只读的,辅助记忆:const在*右边离指针比较近,故作用于指针上。
1、结构体struct注意事项
结构的定义后面可以直接跟变量名,表示这些变量的类型是这个结构。例如:struct { *** } vol, rate ;这样就定义了两个结构体变量vol和rate。理解:跟基本类型变量的定义int number ;本质相同 ,可以认为 struct { *** } 就类似于系统内部类型定义int,只是类型不同而已。
缺点是:无法利用这个 struct{ *** } 再进行新的变量定义了。
解决方案就是:struct后边增加“结构标签”类似于struct tag { *** } ; 这样以后再定义新变量时,直接用结构体标签:struct tag vol , xxx,xxx, ……;
能不能再优化一点?用typedef进行类型定义,不过这样就无法知道定义的某个变量是不是结构类型了。
结构中允许存在位段、无名字段以及字对齐所需的填充字段。通过在字段的声明后面加一个冒号以及表示字段位长的整数来实现。
[cpp]
struct tag
{
unsigned int inactive :1;
unsigned int :1;
unsigned int test :6;
short pid_id;
struct tag * next;
}
位段的类型必须是int、unsigned int或signed int,int位段的值可不可以取负值取决于编译器。而且尽量不要把结构体的声明和变量的定义混在一起,这样影响代码阅读。
2、联合union注意事项
在联合union中,所有的成员都从偏移地址零开始存储,每个成员位置都重叠在一起,在某一时刻只有一个成员真正存储于该地址。优点是:可以节省存储空间;缺点是:需要程序员时刻牢记自己存储的数据类型,以便用合理的方式解释数据。
还有就是可以把同一种数据解释成两种不同的东西,尤其是在嵌入式硬件编程时使用较多。
例如:
[cpp]
union bit_tag
[cpp]
{
uint_8 state;
struct
{
uint_8 bit_1 :4;
uint_8 bit_2 :4;
}BIT;
[cpp]
}
3、枚举enum注意事项
枚举就是简单的把一串名字和一串整型值联系在一起。默认情况下,整型值从0开始,如果对表中某个标识符进行赋值,那么紧接其后的那个标识符就比这个大1,依次类推,直到到达下一个手动赋值的数值开始,继续依照新的基准值开始计数。
优点:#define定义的名字在编译时就被丢弃了(预处理阶段替换掉了),而枚举名字在调试器中可见,可以在调试时使用。枚举类型定义的变量,在系统中会有类型检查,而#define则没有,所以推荐用枚举。
补充:软件开发 , C语言 ,