描述一些复杂对象时经常用到结构体,结构体是c语言自带类型的集合
比如一个学生类型的定义
struct Stu
{
char name[20];
int age;
int id;
}S1;
struct是结构体关键词,后面跟着要结构体类型,可以理解为标签,是将该结构体类型区别与其它结构体类型的符号。接着是大括号,里面是结构体成员,可以是自带类型,也能是自定义类型,不过不能赋初值,只是一个类型的声明。S1是该结构体类型的一个变量,属于全局变量。注意在声明最后要写一个分号,并且结构体不能自引用,也就是不能包含自己。
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], * p;
还有一种特殊声明,就是不写结构体名称,这种声明的变量创建只能在最后的分号之前创建。现有语句p = &x,该表达式是否合法?编译器会将两个声明当成两个不同的结构体类型,两个不同类型当然不能这样赋值。
struct Stu
{
char name[20];
int age;
};
int main()
{
struct Stu s = { "zhangsan",18 };
return 0;
}
struct Stu是一种类型像int一样,接着是结构体变量名,用大括号初始化结构体,里面的元素用逗号隔开。
内存对齐规则
struct S1
{
char c1;
int i;
char c2;
};
c1先占用一个字节,但i为整形对齐数为4,存储到偏移量为4的倍数的地址处,浪费了3字节,整形存储又用了4个字节,c2对齐数为1,占用1字节,结构体大小为最大对齐数的整数倍,现在结构体为9字节,最后结构体为12字节,4的整数倍。
struct S2
{
char c1;
char c2;
int i;
};
c1与c2占用2字节,i对齐到偏移量为4的整数倍处,浪费2字节,最后为8字节。
struct S3
{
double d;
char c;
int i;
};
double8字节,char1字节,int对齐时浪费3字节,自己时4字节,此时16字节,为最大对齐数8的整数倍。
struct S4
{
char c1;
struct S3 s3;
double d;
};
c1占用1字节,s3为结构体,s3的最大对齐数为8,浪费7字节,加上自己16字节,d是8字节,最后是32字节。
#pragma pack(n)//将默认对齐数修改成n
#pragma pack()//将默认对齐数重置回原来的值
当我们用结构体传参时,尽量使用结构体指针,当结构体太大时,作为实参的临时拷贝的形参会占用较多的空间,造成空间的浪费。我们在结构体传参时尽量使用指针。
位段的成员必须是signed int,unsigned int,或者char。位段的空间是按照1个或4个字节开辟的。
struct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
在结构体成员后加上冒号与数字来表示该成员所占的位。因为是char先开辟一个字节,a使用3个bit,b使用4个bit,c要使用5
个bit,有的编译器会将剩下的一个bit使用,有的则会再开辟一个字节来存放c。假设vs会再开辟一个字节,存放d时因为放不下又开辟一个字节。所以S结构体大小是3个字节。(冒号后的数字不能大于类型)
但位段存在许多跨平台问题
1.int位段被当作无符号还是有符号是不确定的
2.位段中最大位的数目不能确定,在16位机器与32位机器,在32位机器中写27换作16位机器会出现问题。
3.位段中成员是从左向右存储,还是从右向左标准还未定义。
4.当剩余空间无法存储下一个成员时,浪费剩余空间还是利用标准也未确定。
跟结构体相比,位段的空间更小,能很好地节省空间,但其跨平台性差。
enum Color//枚举的声明
{
red,
buld,
green
};