一、结构的声明
1、两个无名结构体声明的结构体变量类型不相同,不可以直接相互赋值。例如:
struct {
int a;
char b;
float c;
} x;
struct {
int a;
char b;
float c
} *z;
z = &x; 这条语句是错误的,即使他们的成员列表完全相同。
二、几个操作符的优先级
1、指向结构体成员操作符->和下标引用操作符[ ]和点操作符具有相同的优先级,结合性都是从左向右;
2、间接访问操作符* 和 取地址符优先级相同,它们是单目运算符,结合性从右向左,并且它们的优先级都小于上述三个操作符。
三、结构的自引用只能引用指向其类型本身的指针,而不能是一个完整的结构,否则会陷入无限递归,因为如果结构引用完整自身类型时,此时结构还没有完全声明,大小未确定。例如:
struct self_ref {
int a;
struct self_ref b;
char c;
}; 这是错误的,但是下面的这个是正确的,因为此时b是一个指针,占用空间大小是固定的,
struct self_ref {
int a;
struct self_ref * b;
char c;
};
注意,下面这个声明也是错误的,
typedef struct {
int a;
self_ref * b; //此时self_ref还没有定义
char c;
} self_ref; 可以使用标签来声明b,例如:
typedef struct self_ref_tag {
int a;
struct self_ref_tag * b; //此时self_ref_tag 已经定义
char c;
} self_ref; //此后,可以用self_ref来定义struct self_ref_tag 类型的结构体变量
四、结构的不完整声明,是为了解决两种不同的结构体类型之间的相互引用,例如:
struct B;
struct A {
int a;
struct B b;//如果不首先对struct B进行不完整声明,此处的struct B会是未定义。
char c;
};
struct B {
int i;
struct A a;//此时,struct A 已经完整声明
float f;
};
五、结构体的边界对齐
1、编译器为结构变量成员分配内存时要满足边界对齐的要求,虽然这可能会浪费部分内存空间。
2、根据边界对齐要求降序排列成员列表,可以最大限度的减少浪费的内存空间;
3、sizeof的返回值包含了浪费的内存空间。
六、结构体的位段
1、位段的成员必须声明为int 或者signed int 或者unsigned int ,并且建议尽量显示的声明,因为int位段被当做有符号还是无符号和具体的系统有关;
2、要注意位段中的位的最大数目,编译器会将位段的最大的长度限制在一个整型值得范围内,所以一个能够运行在32位机器上的位段声明可能在16位的机器上无法运行。
3,、位段的成员在内存中是从左向右还是从右向左分配也和具体的系统有关;
4、当一个声明指定了两个位段,第二个位段比较大,无法容纳于第一个位段剩余的位时,编译器有可能将第二个位段放在内存的下一个字,也可能直接放在第一个位段的后面,从而能在两个内存位置的边界上形成重叠。
5、带有位段声明的程序要考虑移植性。
七、联合
1、联合的初始化,其初始值只能初始化一个值,并且是其第一个成员的类型,否则编译器会尝试强制转换为第一个成员的类型。
2、编译器在对联合类型变量进行内存分配时,会根据最长的成员进行分配,联合的所有成员引用相同的内存位置。
3、联合的长度就是它最大成员的长度。