【基本语法】结构体&共用体&枚举详解

一、结构体详解

1.结构体概述

  1. 结构体作用
    结构体是一种自定义数据类型,可以解决数组类型单一的缺陷,即定义的结构体类型可以包含多种数据类型;
  2. 结构体的存储
    结构体在内存中是一块连续存储的空间,类似于多维数组,因此有下标和指针两种访问方式:
struct student{	
	char *name;
	int num;
	double score;
}s1;			//定义变量
int main(void)
{
	struct student *s2 = &s1;	//定义变量
	s1.name = "s1";
	s1.num = 1;
	s2->score = 3.14;	//赋值

	printf("s1.name = %s\n", s1.name);		//下标访问
	printf("s1.num = %d\n", *((int *)((int)&s1 + sizeof(char *))));	//指针访问
 	printf("s1.score = %f\n", s2->score);	//指针访问
}
  1. 结构体变量名
    结构体变量名代表的是整个结构体,因此无论是值还是地址,都代表着整个结构体;
struct str{				//定义结构体类型
	char a;
	char c;
};
int main()
{
	struct str s1 = {	//定义结构体变量
		s1.a = 'a',
		s1.c = 'a'
	};
	printf("&s1 = %p\n", &s1);	//输出 &s1 = 0136F890	结构体整体首地址,子数值上等于第一个元素的地址
	printf("s1 = %x\n", s1);	//输出 s1 = 6161	即两个元素s1.a和s1.c的值
	printf("sizeof(s1) = %d\n", sizeof(s1));	//输出 sizeof(s1) = 2  即整个结构体的大小
	printf("&s1.a = %p\n", &s1.a);		//输出 &s1.a = 0136F890 即结构体首元素的地址。
}

2.结构体对齐访问

  1. 对齐访问的原因
    硬件、外设、Cache等都要求四字节访问可以提高访问效率;

  2. 对齐访问规则
    (1)32bit编译器默认4byte访问:结构体整体大小必须4字节对齐(4的倍数);
    (2)结构体中的元素也必须对齐存放:元素首地址为是4的倍数,结束地址取决于下一个元素大小:若两个元素大小相加可以填充,则组合起来需要4字节对齐;
    (3)编译器考虑结构体存放时,以满足以上要求的最少内存需要的排布来算。

  3. 字节对齐的指令
    (1)#pragma pack()#pragma pack(n):以#pragma pack(n)为始,以#pragma pack()为止的范围内的结构体成员按n字节对齐:

#pragma pack(1)			//以1字节对齐
struct stu {
char c;
int num;
}#pragma pack()
sizeof(stu) == 5;		//该结构体占用5字节而非8字节

(2)__attribute__((packed))__attribute__((aligned(n))):直接放在对齐类型后义,范围是当前__attribute__((packed))__attribute__((aligned(n)))的类型,作用域结构体整体而非单独的成员;__attribute__((aligned(n))):使结构体整体以n字节对齐;__attribute__((packed)):取消结构体整体的对齐方式,即结构体实际占用空间大小;

struct stu {
	char c;
	int num;
}__attribute__((aligned(4))//stu整体4字节对齐
sizeof(stu) == 8;

struct stu{	
	char c;
	int num;
}__attribute__((packed));		//stu实际占用空间大小
sizeof(stu) == 5;

二、共用体详解

共用体概述

  1. 共用体类型、变量的定义与结构体相同,使用方法与结构体类似;
  2. 共用体内部所有成员共用一个内存空间,因此对一个成员赋值即对所有成员赋值;
  3. 各成员之间的区别只是数据类型不一样即解析的方式不一样;
  4. 共用体的大小等于成员中占最大内存的数据类型的大小,且由于共用一个内存空间,因此不涉及字节对齐;
//定义共用体
union stu{
	char a;
	int b;
	float c;
}s1;			//定义共用体变量
int main(void)
{
	//定义共用体变量
	union stu s1;
	s1.b = 97;	
	//访问共用体
	printf("s1.a = %c\n", s1.a);		//输出 s1.a = a
	printf("s1.b = %d\n", s1.b);		//输出 s1.b = 97
	printf("s1.c = %f\n", s1.c);		//输出 s1.c = 0.000000	即三个元素实际为同一个值
	printf("sizeof(s1) = %d\n", sizeof(s1));	//输出 sizeof(s1) = 8 即最大的元素double的大小
};
  1. 共用体本质上也可以通过指针和强制类型转换来代替
//通过强制类型转换,从s1.a得到s1.b
char *pc = &a;
printf("s1.b = %d\n", *((int *)pc));	

三、枚举详解

1.枚举概述

  1. 枚举的作用
    枚举通过声明符号来表示整型常量,来提高代码的可读性和直观,通常用在有些变量的取值被限定在一个有限的范围内,如一周从周一到周日,每月1号到31号等;
  2. 定义
    枚举的语法与结构体类似
enum color{		//定义枚举类型
	red,
	green,
	blue =4,
	yellow,
}c1;			//定义枚举变量

int func1()
{
	enum color c2;			//定义枚举变量
	c1 = red;				//使用枚举
}
  1. 枚举符
    (1)枚举类型的成员称为枚举符(如red、yellow等),枚举符本质是整型常量,因此可以用枚举符代替所有使用整型常量的地方,如声明数组的大小等:int str[yellow] = {0, 1, 2, 3}
    (2)枚举符所代表的整型常量默认从0开始(如red == 0),依次向后排(如green默认为1);但可以自定义(如blue = -4),自定义之后的值根据自定义的值向后排(如yellow = -5);

2.枚举与宏定义区别

  1. 相同点
    枚举与宏定义都可以通过字符来代替某个常量,是代码更直观,二者之间大部分情况下可以替换通用。
  2. 不同点
    枚举通常用在有顺序或某些常量的有限集合中,而宏定义更多用在独立的,相互之间无关联的定义之中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值