结构体 位段 枚举 联合体

本文详细介绍了结构体的声明、匿名结构体、自引用结构体、内存对齐规则、位段概念及其应用,以及枚举和联合(共用体)的使用。通过实例演示,探讨了结构体大小计算和跨平台问题,提供了优化内存对齐和结构体参数传递的策略。
摘要由CSDN通过智能技术生成

结构体

结构体的声明

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

回忆 一下 我们 学过的 集合 。数组是不是一种集合, 数组 相比 结构体,数组的元素是 一组相同元素的集合。 (结构是 不同类型)

例如

struct tag
{
member-list;
}variable-list

写法一

struct 关键字
Stu ---》 标签 
struct Stu   
{
    // 相关属性
    char name[20];//名字
    int age;//年龄
    char sex[5];//性别
    char id[20];//学号
}; //分号不能丢

写法二

通过 Struct Stu 创建 两个全局 变量 s1 和 s2, 在 main 函数 中 通过 Struct Sut 创建 局部变量 s3

struct Stu {
	// 学生的相关属性
	char name[20];
	int age;
}s1,s2;



int main()
{
	// s3 局部变量
	struct Stu s3;
	return 0;
}

特殊声明 匿名结构体

在声明结构的时候,可以不完全的声明。

此时 只能 使用一次 。 使用 匿名结构体 创建了一个变量 s1

//匿名结构体类型
struct  {
	// 学生的相关属性
	char name[20];
	int age;
}s1;

匿名结构体特点

//匿名结构体类型
struct
{
    int a;
    char b;
    float c;
}x;
struct
{
    int a;
    char b;
    float c;
}a[20], *p

这里 两个匿名结构体的 成员 相同,那么 我们是不是 可以 &x 放入 p 中?

struct
{
	int a;
	char b;
	float c;
}x;
struct
{
	int a;
	char b;
	float c;
}a[20], * p;

int main()
{
	p = &x;
	return 0;
}

在这里插入图片描述

可以看到这里 报出 警告,这里 编译器 会认为

x 的 类型 与 p 的 类型 不一样 所以这里就会报警。

编译器会把上面的两个声明当成完全不同的两个类型

结构的自引用

在结构中包含一个类型为该结构本身的成员是否可以呢?

错误自引用 方式 结构体 存放自己 类型

//代码1
struct Node
{
int data; // 4 
struct Node next;
};
//可行否?
如果可以,那sizeof(struct Node)是多少?

这里就会出现一个 问题,每次 计算 大小的时候,我们 先计算 ,一个 int 的 大小,然后 遇到一个 struct Node next; 又进入 到一个结构体,又会遇到一个int 计算后 同样 在 遇到 一个 struct Node next 此时就会形成 一个 死循环,无线套娃下去。所以这种 创建 是 错误的。

正确的自引用 方式 结构体存放下一个结构的 地址

//代码2
struct Node
{
    int data;
    struct Node* next;
};

上面我们学习了 匿名结构体,那么这里这样写代码能吗?

//代码3
typedef struct	
{
    int data;
    Node* next;
}Node;
//这样写代码,可行否?

这里 是 错误的,

来看 这里 我们 Node* next ,这里 我们 typedef重新命名的 Node 是 在 后面,这里就会出现问题、这里我们还没知道 这个重命名的Node这里就先使用上了,就会 形成 先有鸡 还是 先有蛋的问题。

解决方式

//解决方案:
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

结构体变量的定义和初始化

struct Point
{
    int x;
    int y;
}p1; //声明类型的同时定义变量p1

struct Point p2; //定义结构体变量p2

//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};

struct Stu     //类型声明
{
    char name[15];//名字
    int age;    //年龄
};

struct Stu s = {"zhangsan", 20};//初始化

struct Node
{
    int data;
    struct Point p;
    struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化

struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化


int main()
{
    Struct Point s1 = {2,3};
    //创建 s1 初始化 x = 2, y = 3
}

结构体内存对齐(重点)

计算结构体 大小

  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的值为8
  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
    体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

练习

//练习1
struct S1
{
    char c1; // 1 字节
    int i; //  4 字节
    char c2;// 1字节
};
printf("%d\n", sizeof(struct S1));

这里 按照上面 引用 的 规则 我们来计算一下结构体的 大小

在这里插入图片描述

看完上面的 那么 你能来练习一下吗?

熊猫人手持鞭子-表情包原图-表情包模板

//练习2
struct S2
{
    char c1;
    char c2;
    int i;
};
printf("%d\n", sizeof(struct S2));

在这里插入图片描述

你有没有答对呢?
在这里插入图片描述

是不是 还不过瘾, 我还不懂你们 ,那么 接下来 这里还有嘿嘿。
在这里插入图片描述


//练习3
struct S3
{
    double d; 
    char c;
    int i;
};
printf("%d\n", sizeof(struct S3));

这里就 不画图 了 这里, d 的大小 为 8 那么 是不是 占的大小就算 0 -> 7, c 就 占 8 地址处, 那么 此时 8 为 4 的倍数,但被占用了 只能找 下一个 4 的倍数,12

那么 i 就 在 15 地址 处 ,此时 最大对齐数 不就是 8 吗 ,那么 结构 体大小只需要 找 8的 倍数,此时正好 0 - 15 大小为 16,那么 这个结构体大小就为 16

//练习4-结构体嵌套问题
struct S4
{
    char c1;
    struct S3 s3;
    double d;
};
printf("%d\n", sizeof(struct S4));

这里就 有趣了 我们的结构体 居然 含有 另外一个结构体,是不是 很有趣,那你 能 先 来计算一下 这个 结构体大小吗??

查看源图像

在这里插入图片描述

这里 我们 还能使用 offsetof 来观察 我们 的 偏移量

在这里插入图片描述

#include<string.h>
#include<stddef.h>

int main()
{
    printf("%d\n", offsetof(struct S1, c1));
    
    printf("%d\n", offsetof(struct S1, i));
    
    printf("%d\n", offsetof(struct S1, c2));
    return 0;
}

在这里插入图片描述

那么 这里为什么存在内存对齐?

大部分的参考资料都是如是说的:

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

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。

在这里插入图片描述

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起。

回忆一下 刚刚的

//例如:
struct S1
{
    char c1;
    int i;
    char c2;
};
struct S2
{
    char c1;
    char c2;
    int i;
};

这里 s1 是不是 12 s2 是不是 8,这里 都为 char 和 i ,那么s2 将 char 放在了一起是不是 就 减少了 空间的浪费? 

#pragma 修改默认对齐数

在vs中 我们拥有默认对齐数 8,如果我们 想要修改默认对齐数,可以通过 #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;
}

在这里插入图片描述

结论:
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数

结构体传参

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.位段的成员必须是 int、unsigned int 或signed int 还有 char。(整形家族即可)
2.位段的成员名后边有一个冒号和一个数字。

struct A
{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
};

对比一下 结构体
 struct A
{
    int _a;
    int _b;
    int _c;
    int _d;
};

 只差 : 和 数字。

A就是一个位段类型。

那位段A的大小是多少?

答案 是 8byte

在这里插入图片描述

  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

接下来我们 继续来看一个例子

//一个例子
struct S
{
    char a:3;
    char b:4;
    char c:5;
    char d:4;
};
struct S s = {0};
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;
//空间是如何开辟的?

在这里插入图片描述

位段的跨平台问题

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
    器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
    舍弃剩余的位还是利用,这是不确定的

总结:

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

位段的应用

在这里插入图片描述

枚举

枚举顾名思义就是一一列举。

把可能的取值一一列举。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举

这里就可以使用枚举了。

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

enum Sex//性别
{
    MALE,
    FEMALE,
    SECRET
}enum Color//颜色
{
    RED,
    GREEN,
    BLUE
}

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。

这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值

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

枚举的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 防止了命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个常量

学完了 结构 体,位段,枚举这里就 来 完成 一个通讯录,来 熟悉 这些知识点

通讯录

#define _CRT_SECURE_NO_WARNINGS 1


#include"contact.h"

// 通讯录
// 1.通讯录中能 存放1000个人的信息
// 每个人的 信息
// 名字 + 年龄 + 性别 + 电话 + 地址
// 2. 增加人的信息
// 3. 删除指定人的信息
// 4. 修改指定的信息
// 5.查找指定人的信息
// 6.排序通讯录的信息

void mune()
{
	printf("************************\n");
	printf("*** 1.add    2.sub   ***\n");
	printf("*** 3.revise 4.find  ***\n");
	printf("*** 5. sort  6.print ***\n");
	printf("****     0.exet      ***\n");
	printf("************************\n");


}
enum on
{
	exet,
	add,
	sub,
	revise,
	find,
	sort,
	print
};
int main()
{
	int inpt = 0;
	P con;
	Initcontact(&con);
	do {
		mune();
		printf("请选择\n");
		scanf("%d", &inpt);
		switch (inpt)
		{
		case add:
			addcontact(&con);
			break;
		case sub:
			subcontact(&con);
			break;
		case revise:
			revisecontact(&con);
			break;
		case find:
			findcontact(&con);
			break;
		case sort:
			sortcontact(&con);
			break;
		case exet:
			break;
		default:
			printf("选择错误重新选择\n");
			break;
		case print:
			printcontact(&con);
			break;
		}


	} while (inpt);
}

函数声明

#pragma once

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>

#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 20
#define MAX_ADDR 10
#define MAX 1000

typedef struct peoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char tele[MAX_TELE];
	char addr[MAX_ADDR];

}peoInfo;

typedef struct Contacts
{
	peoInfo data[MAX];
	int sz;
}P;

void Initcontact(P* Ps);
void addcontact(P* ps);
void printcontact(P* ps);
int FindByName(P* ps);
void subcontact(P* ps);
void revisecontact(P* ps);
void findcontact(P* ps);
void sortcontact(P* ps);
int girl(P* ps);

函数实现

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void Initcontact(P* ps)
{
	assert(ps);
	ps->sz = 0;
	memset(ps->data, 0, sizeof(ps->data));
}


void addcontact(P* ps)
{
	assert(ps);
	if (ps->sz == MAX)
	{
		printf("通讯录已满,无法添加\n");
	}
	printf("请输入名字");
	scanf("%s", ps->data[ps->sz].name);
	printf("请输入年龄");
	scanf("%d", &ps->data[ps->sz].age);
	printf("请输入性别");
	scanf("%s", ps->data[ps->sz].sex);
	printf("请输入电话");
	scanf("%s", ps->data[ps->sz].tele);
	printf("请输入地址");
	scanf("%s", ps->data[ps->sz].addr);

	ps->sz++;
	printf("添加成功\n");
}
void printcontact(P* ps)
{
	assert(ps);
	int i = 0;
	printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < ps->sz; i++)
	{
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[i].name,
												   ps->data[i].age,
												   ps->data[i].sex,
												   ps->data[i].tele,
												   ps->data[i].addr);
	}

}


int FindByName(P* ps,char name[])
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (strcmp(ps->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void subcontact(P* ps)
{
	assert(ps);
	char name[MAX_NAME];
	printf("请输入要删除联系人的名字\n");
	scanf("%s", name);
	if (ps->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
	}
	int pos = FindByName(ps, name);
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		int i = 0;
		for (i = pos; i < ps->sz - 1; i++ )
		{
			ps->data[i] = ps->data[i + 1];
		}
	}
	ps->sz--;
}


void revisecontact(P* ps)
{
	char name[MAX_NAME];
	printf("请输入要修改人的名字\n");
	scanf("%s", name);
	int a = 0;

	if (ps->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
	}
	int pos = FindByName(ps, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
	}
len:
	printf("如果只需修改名字,请按1\n");
	printf("如果只需修改年龄,请按2\n");
	printf("如果只需修改性别,请按3\n");
	printf("如果只需修改电话,请按4\n");
	printf("如果只需修改地址,请按5\n");
	printf("如果需要自行更改,请按6\n");
	scanf("%d", &a);
	printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
		ps->data[pos].age,
		ps->data[pos].sex,
		ps->data[pos].tele,
		ps->data[pos].addr);
	if (a == 1)
	{
		printf("请输入需要修改的姓名\n");
		scanf("%s", ps->data[pos].name);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}
	else if (a == 2)
	{
		printf("请输入需要修改的年龄\n");
		scanf("%d", ps->data[pos].age);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);

	}
	else if (a == 3)
	{
		printf("请输入需要修改的性别\n");
		scanf("%s", ps->data[pos].sex);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}
	else if (a == 4)
	{
		printf("请输入需要修改的电话\n");
		scanf("%s", ps->data[pos].tele);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}
	else if (a == 5)
	{
		printf("请输入需要修改的地址\n");
		scanf("%s", ps->data[pos].addr);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}

	else if (a == 6)
	{


		printf("请输入要修改的信息\n");
		printf("请输入名字");
		scanf("%s", ps->data[pos].name);
		printf("请输入年龄");
		scanf("%d", &ps->data[pos].age);
		printf("请输入性别");
		scanf("%s", ps->data[pos].sex);
		printf("请输入电话");
		scanf("%s", ps->data[pos].tele);
		printf("请输入地址");
		scanf("%s", ps->data[pos].addr);
		printf("修改成功,通讯录保存为\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);

	}
	else
	{
		printf("输入错误,重新输入\n");
		goto len;
	}
}
void findcontact(P* ps)
{
	assert(ps);
	char name[MAX_NAME];
	printf("输入要查找信息的姓名\n");
	scanf("%s", name);
	if (ps->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
	}
	int pos = FindByName(ps, name);
	if (pos == -1)
	{
		printf("查找失败,通讯录未有此人\n");
	}
	else
	{
		printf("查找成功\n");
		printf("%-5s\t%-5s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-5s\t%-5d\t%-5s\t%-20s\t%-20s\n", ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}
}

//判断性别
int girl(P* ps, int n)
{
	assert(ps);
	if (strcmp(ps->data[n].sex, "男") == 0)
	{
		return n;
	}
	else if (strcmp(ps->data[n].sex, "女") == 0)
	{
		return girl(ps, n + 1);
	}
}

// 按照名字排序
int cmp(const void * e1,const void* e2)
{
	return strcmp(((peoInfo*)e1)->name, ((peoInfo*)e2)->name);
}
int cmp2(int a, int b)
{
	return a - b;
}
void sortcontact(P* ps)
{
	assert(ps);
	printf("请选择按照年龄排序,还是按照姓名排序\n");
	printf("按照年龄请按一,名字请按0\n");
	int n = 0;
	scanf("%d", &n);
	if (n == 1)
	{
		qsort(ps->data, ps->sz, sizeof(peoInfo), cmp2);
		return;
	}
	qsort(ps->data,ps->sz,sizeof(peoInfo), cmp);
}

联合(共用体)

联合类型的定义

联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间(所以联合也叫共用体)

在这里插入图片描述

	//联合类型的声明
union Un
{
    char c;  -- 1
    int i;  -- 4  
        所以 这个联合体的大小位 4 
};
//联合变量的定义
union Un un;

//计算连个变量的大小
printf("%d\n", sizeof(un)) 
    答案 是 4  

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联
合至少得有能力保存最大的那个成员)

联合体的特点

这里 我们 是 联合 体,那么 改变其中一个变量的 值 ,另外 的 变量 同样 也会 更改

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

// 下面输出的结果是一样的吗?
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));

//下面输出的结果是什么?
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);

在这里插入图片描述

这里就是联合体的 特点

这里 我们 来通过 联合体来判断 机器 的 存储方式 大端还是 小端

之前我们 判断 大小端 的做法,

int tmp()
{
	int a = 1;
	char* p = (char*)&a;
	return *p;
	
}
int main()
{
	int ret = tmp();
	if (ret == 1)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
}

下面 我们 可以使用 联合体
    int tmp2()
{
	union 
	{
		char a;
		int i;
	}u;
	u.i = 1;
	return u.a;
}
int main()
{
	int ret = tmp();
	if (ret == 1)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
}
这里就是通过 结构 体 的 特点,将 1 存入 结构体中,如果 取出的 是 1 那么就是小端,如果 取出的是0 那么就算 大端

联合大小的计算

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

union Un1
{
    char c[5];  --》 相当于 5char  对齐数 为1
    int i; --4 对齐数 为 4
        5 不是 4 的 倍数,所以这个联合体的大小 为 8
    
};
union Un2
{
    short c[7]; --》这里相当于 7short  这里 最大 对齐数 就为2 
    int i; --4 对齐数为 4  
        那么 先开 7*2 个 大小, 14 不是 4的 倍数,那么 找 4 的倍数 ,所以 这个联合体的 大小就为 16
};
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));  8
printf("%d\n", sizeof(union Un2));  16

在这里插入图片描述

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值