自定义类型:结构体,枚举,联合体

目录

一、结构体

1、结构体的声明与初始化

2、结构体大小的计算

3、结构体传参

二、枚举

1、枚举的定义。

2、枚举的使用

三、联合体

1、联合体的定义

2、联合体的大小计算


一、结构体

1、结构体的声明与初始化

结构体常见的声明方式有三种,如:

1、
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};
//创建结构体变量
struct stu s1;
//初始化结构体
s1 = { {"zhangsan"},18,{"man"},{"123"} };
//当然可以边创建结构体变量边初始化;
struct stu s2={ {"zhangsan"},18,{"man"},{"123"} };

2、
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}s1,s2;
//结构体的创建和初始化与上面相同

3、
typedef struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}Stu;
//结构体变量的创建,这种结构体创建就不用写”struct stu“,而是直接写他们的别名就行。
Stu s1;
//然后初始化与上面类似。

第一种是直接声明一个结构体;第二种是在声明的同时创建了两个全局的结构体变量s1,s2;第三种是给声明的结构体创了一个别名“Stu”。这个别名的作用体现在创建结构体变量的方式:第一种、第二种创建结构体变量是:struct stu s1,这个s1就是结构体变量;而第三种创建结构体变量是:Stu s1,这个s1也是一个结构体变量,别名的作用就体现在这。

结构体还有一种特殊声明:在声明结构体的时候,不用起名字,这种结构体就是匿名结构体。

struct
{
	int a; 
	char b;
	float c;
}x;

但是声明这种结构体的同时,要把结构体变量同时创建,在其他地方就不能创建结构体变量了。

2、结构体大小的计算

首先我们先了解结构体的对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数=编译器默认的一个对齐数与该成员人小的较小值。

VS中默认的值为8   Linux中的默认值为4
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

下面我们来做几道题来理解一下

struct S1
{
 char c1;
 int i;
 char c2;
};

 c1是char类型大小是1,vs默认是8,对齐数取较小值,所以这个变量的对齐数是1,而其实偏移量是0,是1的倍数,所以可以放下c1。i的大小是4,vs默认是8,所以这个变量的对齐数是4,而此时的偏移量是1,不是对齐数的整数倍,所以不能放,要舍弃3个字节,到偏移量为4的地方放下i。放完i后到了偏移量为8的位置,c2变量的对齐数是1,8是1的倍数可以放c2,放完c2后到了偏移量为9的位置,不是最大对齐数4的倍数,所以我们要舍弃3个字节,到偏移量为12的位置。因此整个结构体的大小为12.

那么为什么要内存对齐呢?

1.平台原因(移植原因)︰不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
⒉性能原因︰数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说︰
结构体的内存对齐是拿空间来换取时间的做法。

3、结构体传参

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;
}

上面那种传参方式好呢?

答案是传地址那种好。因为如果按值传参,我们需要把整个结构体传过去,传参是需要压栈的,如果结构体过大,系统的开销就比较打。而如果我们按址传参,我们只需要传一个地址过去,所需的系统开销就比较小。

二、枚举

1、枚举的定义。

枚举使用关键字 enum

enum Day//星期
{
 Mon,
 Tues,
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};

 其中Mon的默认值是0,Tues的默认值是1,以此类推sun的默认值是6。

但如果这样写:

enum Day//星期
{
 Mon,
 Tues,
 Wed,
 Thur=10,
 Fri,
 Sat,
 Sun
};

 Mon的是0,Tues是1,Wed是2,Thur是10,Fri是11,Sat是12,sun是13,。

2、枚举的使用

enum Color//颜色
{ 
 RED=1, 
 GREEN=2, 
 BLUE=4 
}; 
enum Color clr = GREEN;

只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。如果写成clr=1,这样在某些编译器下会报错。

三、联合体

1、联合体的定义

联合体也称共用体

这是一种特殊的自定义类型,这种类型也包含一系列的成员,但这些成员公用一块空间。

联合体的关键字是 union

union Un 
{ 
 int i; 
 char c; 
}; 
union Un un;

下面让我们看看un的空间分布

因为联合体是公用空间的,所以i和c共用一块空间,i占4个字节,c占用一个字节,所以整个联合体是4个字节,且c与i共同使用最低那个地址的空间。

printf("%d\n", &(un.i)); 
printf("%d\n", &(un.c));

 这个结果相同吗?

答案是相同的,因为共用一块空间,所以起始地址都相同。

un.i = 0x11223344; 
un.c = 0x55; 
printf("%x\n", un.i); 

 输出结果是11223355

 机器按小端方式,u.i在空间上是如图这样显示的,后来un.c=0x55,有因为i和c共用一块空间,且c只有一个字节,就将低地址的44改为了55

 

 所以打印11223355。

2、联合体的大小计算

计算规则:

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

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

 

union Un1 
{ 
 char c[5]; 
 int i; 
}; 

数组c的类型是char,对齐数是1,但整个数组占用5个字节,i的对齐数是4,5个字节的空间够i使用,但是5不是最大对齐数4的倍数,所以得浪费3个空间的字节,使联合整个空间大小为最大对齐数的倍数,因此这个联合体占用8个字节的空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值