自定义类型

文章详细介绍了C语言中的结构体,包括其声明、大小规则以及内存对齐的概念。接着讨论了位段的使用,枚举的优势,以及联合体(共用体)如何在同一空间内存储不同类型的成员。同时提到了结构体在传参时的注意事项和内存对齐对性能的影响。
摘要由CSDN通过智能技术生成

目录

结构体

结构体的声明

结构体的大小

默认对齐数的修改

位段

枚举

联合体 (共用体)


结构体

  • 数组是一组相同元素的集合
  • 而结构体则是一些值的集合,结构体的每个成员可以是不同类型
struct book
//struct 关键字,book 标签名,合起来叫做结构体类型
{
    //成员列表,可以是多个不同类型的成员
    char name[20];//书名
    int price;//价格
    char id[12];//出版社 
}a1,a2,a3;//变量列表,全局变量
int main()
{
    //局部变量
    struct book b1;
    struct book b2;
    struct book b3;
    return 0;
}
//匿名结构体,不完全声明
struct 
{
    char name[20];
    int age;
    char school[20];
}s;//结构体变量
//匿名结构体变量只能创建一次
struct A
{
    int a;
    int b;
};
struct B
{
    int c;
    struct A v;
    //一个结构体可以包含另一个结构体
}
//错误自引用
//结构体自身大小未知
struct C
{
    int n;
    struct c d;
    //无法确认结构体大小
    //死递归
}
struct C
{
    int n;
    struct c *d;
    //指向下一个结构体的指针
}
typedef struct Node
{
	int data;
    Node*next;
}Node;
//把struct Node类型重命名为Node
//但是在还没有声明之前就使用了它是不行的
typedef struct Node
{
	int data;
    struct Node *next;
    //正确
}Node;


结构体的声明

struct A
{
  cahr name[20];  
  int age;
  int weight;
  struct B school;
  //嵌入调用
}struct A a={"zhangsan"};
//全局变量
struct B
{
    char shool[20];
};
int main()
{
    struct A a={18,130,{"jialidun"}};
    //按顺序声明
    struct A a={.age=18,.name="zhangsan",.weight=130,.B.shool"jialidun"};
    printf("%s %d %d %s\n", A.name,A.age,A.weight,A.B.school);
    
    return 0;
}


结构体的大小

规则

1.第一个成员对齐到结构体在内存中存放位置的零偏移处(占几字节给几字节)

2.第二个成员开始,都要对齐到一个对齐数的整数倍处

对齐数:结构体成员大小和默认对齐数的较小值

vs:默认对齐数是8

Linux gcc:没有对齐数,结构体成员自身大小

3.结构体的总大小,必须是所有成员的对齐数中最大对齐数的整数倍

4.如果结构体嵌套结构体成员,要将嵌套的结构体成员,对齐到自己的成员中最大对齐数的整数倍处

!结构体的总大小必须是最大对齐数的整数倍,包含嵌套结构体成员中的对齐数的所有对齐数 


 

  • 按照原来的理解方式
  • c1占用1字节,c占用4字节,c2占用1字节,一共也就6字节
  • 但是结构体却不是这样使用空间的

 


 

 


 


 

  • offsetof宏计算结构体成员相较于起始位置的偏移量
  • #include<stddef.h>
  • offsetof(结构体类型,结构体变量)
  • 为什么有对齐?
  • 平台原因,性能原因
  • 结构体的内存对齐是拿空间换时间的做法
  • 尽量把占用空间小的成员放在一起

默认对齐数的修改

  • #pragma comment()
  • #pragma pack()//修改默认对齐数
#pragma pack(1)
//修改默认对齐数为1
struct A
{
char a;
    int b;
    char c;
};
#pragma pack()
//恢复默认对齐数
int main()
{
    printf("%d\n",sizeof(z));
    return 0;
}

 


结构体传参

结构体在传参时尽量使用传址调用

在传递一个结构体时,太大会在压栈时耗费过多的空间,造成性能的下降

位段

位段成员必须是int,unsigned int ,signed int,char类型

位段成员必须后面跟上 : 和数字

位段的空间是按照四字节(int)或一字节(char)的方式来开辟的

最大值为32bit

位段优点比结构体节省空间

但是不能跨平台使用

struct A
{
    //开辟4字节32bit
    int _a:2;
    //_a占2个比特位
    //32-2
    int _b:5;
    //_b占5个比特位
    //30-5
    int _c:10;
    //_c占10个比特位
    //25-10
    int _d:30;
    //_d占30个比特位
    //空间不够,再开辟4字节
    //但是到底是先把之前的15bit用掉,再用之后开辟的空间是不确定的
    //所以位段有很多不确定性,不能跨平台使用
};
int main()
{
    printf("%d\n",sizeof(struct A));
    //8
    
    return 0;
}

枚举

  • 枚举的优点

  • 增加代码的可读性和可维护性

  • 和#define定义的标识符常量比枚举有类型检查,更加严谨

  • 防止命名污染

  • 便于调试

  • 使用方便,可以定义多个常量

#define RED 1
#define 
enum Cal
{
	add,
    sub,
    mul,
    div,
    exit
};
void menu()
{
    printf("***1.add***2.sub***\n");
    printf("***3.mul***4.div***\n");
    printf("***0.exit******\n");
}
int main()
{
    int input =0;
    
    do
    {
        menu();
        scanf("%d",&input);
        switch(input)
        {
            case add:
                {
                    break;
                }
            case sub:
                {
                    break;
                }
            case mul:
                {
                    break;
				}
            case div:
                {
                    break;
                }
            case exit:
                {
                    break;
                }
            default :
                {
                    break;
				}
		}
    }while(input);
    int a
    return 0;
}

联合体 (共用体)

//联合体关键字 union
//多个成员共同享有一个空间
union Un//union Un类型
{
    char c;//1
    int i;//4
    //共用体/联合体
    //c,i共用一个空间
    //联合体的大小至少是最大成员的大小
    //不能一起使用同一片空间
     
};
int main()
{
    union Un u;
    //printf("%d\n",sizeof(u));//?
	//打印为4
    printf("%d\n",&u);
    printf("%d\n",&(u.c));
    printf("%d\n",&(u.i));
    return 0;
}
//判断大小端
int Big()
{
    //此联合体为判断大小端函数所创建
	union Un
	{
		char i;
		int n;
	}u;
	u.n = 1;
	return u.i;
    //返回1是小端,返回0是大端
}
int main()
{
	
	if (Big())
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}
//联合体大小计算
union Un
{ 
    int i;//4,int 类型为 4
    char n[5];//5,char 类型为 1
    //最大对齐数为4,但是5却不是4的倍数所以空间增加到第八个空间 
}

 

总结

联合体的大小至少是最大成员的大小

当最大成员大小不是最大对齐数的整数倍时,需要对齐到最大对齐数的整数倍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值