文章目录
- 1.结构体的基础知识
- 2.结构体的声明
- 3.特殊的声明
- 4.结构体的自引用
- 6. 结构体的内存对齐
- 7.修改默认对齐数
- 8.结构体传参
- 位段
- 1、位段定义
- 2. 位段的内存分配
- 3.位段的跨平台问题
- 4.位段的运用场景
1.结构体的基础知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
2.结构体的声明
描述一个学生
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
3.特殊的声明
//匿名结构体类型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p
p=&x;此时是违法的,两个变量是不同的类型。
4.结构体的自引用
//代码1
struct Node
{
int data;
struct Node next;
};
//可行否?
这样是不行的,此时的结构体是无法知道有多大的。
//代码2
struct Node
{
int data;
struct Node* next;
};
这样才是正确的,此时就是链表的结点;
//代码3
typedef struct
{
int data;
Node* next;
}Node;
//这样写代码,是不行的。编译是有顺序的,无法识别此时的Node
//解决方案:
typedef struct Node
{
int data;
struct Node* next;
}Node;
6. 结构体的内存对齐
知道如何定义结构体之后,就应该要确定结构体的大小。
对齐规则
这样规则的意义
7.修改默认对齐数
#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));//12
printf("%d\n", sizeof(struct S2));//6
return 0;
}
#progma pack(num)//设置默认对齐数为num
#progma pack()//取消设置的默认对齐数,还原为默认值
8.结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
print1和print2相比,传址会比传值好一点,节省空间。
位段
1、位段定义
位段的声明和结构和结构体类似,有两个不同:
位:二进制位。
1.位段的成员必须是整型家族;
2.位段的成员后面必须要有一个冒号和一个数字。
2. 位段的内存分配
- 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
3.位段的跨平台问题
1.int位段被当成有符号数还是无符号数是不确定的。
2.位段中最大位数不能确定(比如,在16为平台中最大是16,在32为平台是32,写成27,在16位平台会出现问题)。
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳与第一个位剩余的位时候,是舍弃剩余的位还是使用,是不确定的。
总结:
和结构体相比,位段可以达到相同的效果,但是可以很好节约空间,但存在跨平台问题。
4.位段的运用场景
可以对里面的成员进行大小的指定,节省空间。