结构体(自定义类型)
目录
1 结构体的声明
1.1 结构的基础知识
1.2 结构的声明
1.3 特殊的声明
1.4 结构的自引用
1.5 结构体变量的定义和初始化
1.6 结构体内存对齐
1.7 修改默认对齐数
1 结构体的声明
1.1 结构的基础知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
1.2 结构的声明
struct tag
{
member-list; //成员列表,成员变量(可一个,可多个)
}variable-list;//变量列表(可选)
struct book
{
char book_name[20];
char author[20];
int price;
char id[15];
}sb3,sb4; //全局变量
int main()
{
struct book sb1;
struct book sb2; //局部变量
return 0;
}
#
#
1.3 特殊的声明
在声明结构的时候,可以不完全的声明。
//匿名结构体类型
struct
{
char book_name[20];
char author[20];
int price;
char id[15];
}sb1,sb2; //全局变量
int main()
{
return 0;
}
//违法,编译器会把上面的两个声明当成完全不同的两个类型
struct
{
char book_name[20];
char author[20];
int price;
char id[15];
}sb1;
struct
{
char book_name[20];
char author[20];
int price;
char id[15];
}* ps;
int main()
{
ps = &sb1;
return 0;
}
1.4 结构的自引用
struct Node
{
int data;
struct Node* next; //同类型结构体的指针
};
int main()
{
struct Node n;
return 0;
}
typedef struct Node
{
int data;
struct Node* next;
}Node;//之前不能直接写Node
int main()
{
Node n;
return 0;
}
1.5 结构体变量的定义和初始化
struct book
{
char book_name[20];
char author[20];
int price;
char id[15];
}sb3, sb4; //全局变量
int main()
{
struct book sb1 = {"KYF","kyf",80,"K1001"};
struct book sb2; //局部变量
printf("%s %s %d %s %s %d\n", sb1.book_name, sb1.author, sb1.price, sb1.id);
return 0;
}
struct stu
{
char name[20];
int price;
};
struct book
{
char book_name[20];
char author[20];
int price;
char id[15];
struct stu s;
}sb3 = { "KY","ky",8,"K100" ,{"ASD",100}}, sb4; //全局变量
int main()
{
struct book sb2; //局部变量
printf("%s %s %d %s %s %d\n", sb3.book_name, sb3.author, sb3.price, sb3.id,sb3.s.name,sb3.s.price);
return 0;
}
1.6 结构体内存对齐
首先得掌握结构体的对齐规则:
第一个成员在与结构体变量偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8,linux=该成员大小
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么存在内存对齐?
大部分的参考资料都是如是说的:
- 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
- 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。
struct S1
{
char c1; // 1/8 0-1
int i; // 4/8 4-8
char c2; // 1/8 9
//4的倍数, 12
};
int main()
{
printf("%d\n", sizeof(struct S1));//12
return 0;
}
struct S2
{
char c1; //1/8 0-1
char c2; //1/8 1-2
int i; //4/8 4-8
};
int main()
{
printf("%d\n", sizeof(struct S2));//8
return 0;
}
struct S3
{
double d; //8/8 0-7
char c; //1/8 7-8
int i; //4/8 8-12
//8的倍数
};
int main()
{
printf("%d\n", sizeof(struct S3)); //16
return 0;
}
struct S3
{
double d; //8/8 0-7
char c; //1/8 7-8
int i; //4/8 8-12
//8的倍数 16
};
struct S4
{
char c1; //1/8 0-1
struct S3 s3;//8/8 8-27
double d; //8/8 27-32
};
int main()
{
printf("%d\n", sizeof(struct S4)); //32
return 0;
}
#
1.7 修改默认对齐数
之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
还没有评论,来说两句吧...