【C语言】进阶——结构体+枚举+联合

news2024/11/18 13:48:49

 ①前言:

在之前【C语言】初阶——结构体 ,简单介绍了结构体。而C语言中结构体的内容还有更深层次的内容。

一.结构体

结构体(struct)是由一系列具有相同类型或不同类型的数据项构成的数据集合,这些数据项称为结构体的成员。

 1.结构体的声明

// 创建结构体
struct student
{
  char name[10];  // 学生名字
  int num;     // 学生学号
  int age;     // 学生年龄
}stu;

struct student 是类型,stu是结构体类型变量

2.结构体的定义和初始化 

2.1结构体的初始化 
struct Stu         //类型声明
{
 char name[15];    //名字
 int age;          //年龄
};
struct Stu s = {"zhangsan", 20};    //初始化
 2.2结构体的自引用
struct Node
{
 int data;
 struct Point p;
 struct Node* next; 
}n1 = {10, {4,5}, NULL};     //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};    //结构体嵌套初始化

3.结构体内存对齐 

首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

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

        VS中默认的值为8

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

struct S1
{
 char c1;
 char c2;
 int i;
};
printf("%d\n", sizeof(struct S1));

 

s1在内存中所占的字节大小是多少?

VS默认对齐数是8

Linux没有默认对齐数自身大小就是其对齐数

首先c1是char类型 占1个字节与8比,8大,对齐数是1,放在偏移量为0的位置

c2也是char 类型对其数是1放在1的整数倍处也就是放在偏移量为1的位置

i是int型占4个字节,最大对其数是4,放在偏移量为4的位置

最后s1偏移量为7一共占用了8个字节,8是最大偏移量4的整数倍,所以s1在内存中占用了8个字节

 3.1为什么存在内存对齐?

    结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到?
    让占用空间小的成员尽量集中在一起。 

1. 平台原因(移植原因):

        不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特 定类型的数据,否则抛出硬件异常。

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访 问。

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

3.2修改默认对齐数

	#pragma pack(8)//设置默认对齐数为8
	#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(8)//设置默认对齐数为8
struct S1
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

3.3offsetof宏

用法:计算偏移量

头文件:#include <stddef.h> 

offsetof (type,member)
struct address {
   char name[50];
   char street[50];
   int phone;
};
   
int main()
{
   printf("address结构中的name 偏移 = %d 字节\n", offsetof(struct address, name));
   //0字节
   printf("address结构中的street 偏移 = %d 字节\n", offsetof(struct address, street)); 
   //50字节  
}
 👊模拟实现
//模拟实现宏offsetof
#define my_offsetof(struct_name, member_name)  (int)&(((struct_name*)0)->member_name)
//例如shtruct S{char a; char b;};
//用宏替换:(int)&(((struct S*)0)->a)
//解释:把结构体的首地址看成0,那么每个成员的地址(减去首地址0)也就是相对于首地址的偏移量,所以取到成员的地址并转换为int型就是偏移量;
 
//注意:以上把0强制转换成struct S*类型之后(把0转换成一个结构体指针类型),那么从0地址往后看就是一个结构体的形式看
//也可以说是在0地址的位置上放了一个结构体;

注:结构体传参主要以传地址为主。

二.位段 

  1. 位指的是二进制位;
  2. 位段的成员必须是 int、unsigned int signed int、char
  3. 位段的成员名后边有一个冒号和一个数字;
  4. 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要;
  5. 不支持跨平台
struct str
{
	int _a : 2;
	int _b : 3;		//后面的数字是bit位,不是字节
};

 

int main()
{
	unsigned char puc[4];
	struct tagPIM
	{
		unsigned char ucPim1;
		unsigned char ucData0 : 1;
		unsigned char ucData1 : 2;
		unsigned char ucData2 : 3;
	}*pstPimData;
	pstPimData = (struct tagPIM*)puc;
	memset(puc, 0, 4);
	pstPimData->ucPim1 = 2;
	pstPimData->ucData0 = 3;
	pstPimData->ucData1 = 4;
	pstPimData->ucData2 = 5;
	printf("%02x %02x %02x %02x\n", puc[0], puc[1], puc[2], puc[3]);
	return 0;
}

puc是一个char数组,每次跳转一个字节,结构体不是,它只有第一个元素单独享用一字节,其他三个元素一起共用一字节,所以puc被结构体填充后,本身只有两个字节会被写入,后两个字节肯定是0,

然后第一个字节是2就是2了,第二个字节比较麻烦,首先ucData0给了3其实是越界了,1位的数字只能是0或1,所以11截断后只有1,同理ucData1给的4也是越界的,100截断后是00,只有5的101是正常的。填充序列是类似小端的低地址在低位,所以排列顺序是00 101 00 1。也就是0010 1001,

所以结果为02 29 00 00

三.枚举

枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。

枚举就是一个对象的所有可能取值的集合 

#include<stdio.h>
enum sex
{
   male,
   female,
   secret,
};

枚举的关键字是enum 在括号内部注意每个成员名后面要加逗号,同时别忘了括号外面的分号

枚举内部的成员被依次赋值为0,1,2

我们假如将female赋值为1,secret就被赋值为2,male赋值为0

3.1枚举的优点 

1.增加代码的可读性和可维护性

2. 和 #define 定义的标识符比较枚举有类型检查,更加严谨。

3. 防止了命名污染(封装)

4. 便于调试

5. 使用方便,一次可以定义多个常量

enum Sex        //枚举的申明定义
{
	Male,        //枚举常量,默认值是0开始,一次递增1
	female,
	secret
};
enum Color
{
	RED=1,        //也可以手动赋值
	GREEN=2,
	BLUE=4
};
int main(){
    enum Sex a = Male;         //枚举顾名思义就是一一列举。
	enum Color b = RED;
	printf("%d %d %d\n", Male, female, secret);
	printf("%d %d %d\n", RED, GREEN, BLUE);
}

 

四.联合(共用体)

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

联合大小的计算 

  1. 联合的大小至少是最大成员的大小。
  2. 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍 
// 联合体/共用体  -  里面的成员同一时间只能用一个

union Un
{
	char c;     // 1
	int i;     // 4
};

union U
{
	short s[7]; // 14
	int i; // 4
};

int main()
{
	union Un u = { 0 };

	printf("%d\n", sizeof(u)); // 输出 4
	// 下面三行输出同样的地址
	printf("%p\n", &u); 
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i)); 

	union U c = { 0 };

	printf("%d\n", sizeof(c)); // 输出 16 内存对齐了(最大对齐数4的倍数)
	printf("%p\n", &c); // 输出
	printf("%p\n", &(c.s)); // 输出
	printf("%p\n", &(c.i)); // 输出

	return 0;
}

 联合体、大小端结合


int check_sys()
{
	union J
	{
		char m;
		int n;
	};
	J s1;
	s1.n = 1;
	return s1.m;
}
int main()
{
	if (check_sys())
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}
int main()
{
  union
  {
    short k;
    char i[2];
  }*s, a;
  s = &a;
  s->i[0] = 0x39;
  s->i[1] = 0x38;
  printf("%x\n", a.k);
  return 0;
}

 union只有2字节,2字节的十六进制只有4位,所以答案CD排除。而位顺序类似小端,低地址在低处,所以39是低地址,在低位,38在高位,所以是3839

 以上就是我对【C语言】结构体的全部介绍了,身为初学者自知有很多不足,望各位大佬指点得以改正!!!感激不尽。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1039786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NVM:node多版本管理的下载安装及使用

NVM&#xff1a;node多版本管理的下载安装及使用 使用之前先卸载node&#xff0c;避免各种奇葩问题导致不成功。win卸载&#xff1a;win > 设置 > 应用 > 应用和功能&#xff0c;找到 node 点击出现卸载按钮并且卸载它。 1、下载安装&#xff1a; https://github.co…

信创之国产浪潮电脑+统信UOS操作系统体验1:硬件及软件常规功能支持情况介绍

一、引言 由于公司要求支持国产信创&#xff0c;最近办公的笔记本电脑换成了软硬件全国产&#xff0c;由于国产操作系统是在开源linux基础上演进的&#xff0c;在换之前&#xff0c;非常担心操作不方便&#xff0c;周边应用软件少&#xff0c;功能差&#xff0c;内心是比较抗拒…

C++:优先级队列模拟实现和仿函数的概念使用

文章目录 使用方法Compare仿函数一些场景模板参数和函数参数 本篇总结优先级队列 使用方法 首先在官网查看它的一些用法 template <class T, class Container vector<T>,class Compare less<typename Container::value_type> > class priority_queue;从…

软件测试之接口测试

1、什么是接口测试 顾名思义&#xff0c;接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型&#xff0c;测试类型又主…

Crypto:MD5

题目 下载了题目给的压缩包解压后&#xff0c;打开文件 使用md5解码器解码后得到&#xff0c;即为flag

DS18B20温度传感器

DS18B20简介 DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器 这种一线总线就是 三线制 SPI DS18B20的 配置寄存器&#xff1a; TM 是测试位&#xff0c;出厂设置就被设置为0&#xff0c;不需要改动&#xff0c; R1、R…

linux————ceph分布式部署

目录 一、概述 特点 1、统一存储 2、高扩展性 3、可靠性强 4、高性能 组件 1、Monitor 2、OSD 3、MOD 4、Objet 5、PG 6、RADOS 7. Libradio 8. CRUSH 9. RBD 10. RGW 11. CephFS 架构图 二、准备工作 三、ceph安装 创建集群目录 修改配置文件 安装 初…

数据结构上机1

1、题目&#xff1a; 将1~10存入数组a[10]&#xff0c;并将其逆序输出 #define _CRT_SECURE_NO_WARNINGS 1 //(1) 将1~10存入数组a[10]&#xff0c;并将其逆序输出#include <stdio.h>int main() {int a[10];// 将1到10存入数组a[10]for (int i 0; i < 10; i){a[i] i…

[硬件基础]-快速了解I2C串行通信协议

快速了解I2C串行通信协议 文章目录 快速了解I2C串行通信协议1、硬件接口2、数据帧3、数据操作4、时钟拉伸&#xff08;Clock Stretching&#xff09;5、总线仲裁6、权衡&#xff1a;功率与速度7、总结 内部集成电路协议&#xff08;Inter-Integrated Circuit Protocol&#xff…

TS编译选项——TS代码错误不生成编译文件

一、TS不生成编译文件 在tsconfig.js文件中配置noEmit属性 {"compilerOptions": {// outDir 用于指定编译后文件所在目录"outDir": "./dist", // 将编译后文件放在dis目录下// 不生成编译后的文件"noEmit": true,} } 二、TS代码错…

看到一个外贸经典案例, 分享一下

最近看到一个经典案例&#xff0c;案例可能没有多少新奇&#xff0c;但是大家的评论以及给出的解决方案却能给我们很多启发&#xff0c;一个事情要从多方面去进行假设然后一一排除去找到最合适的解决方法&#xff0c; 下面&#xff0c;让我们一起来看看这个外贸小伙伴遇到的问…

《你好,C语言》:从另一个视角学习并重新审视C语言的意义

《你好&#xff0c;C语言》&#xff1a;从另一个视角学习并重新审视C语言的意义 尽管C语言诞生了这么多年&#xff0c;但是它依然活跃在开发者一线&#xff0c;不可否认的是C语言的确有它独特的魅力。本文将从一个全新的视角&#xff0c;重新带领大家学习领悟C语言的奥秘&#…

[XR-FRAME] 1.O3 文档导览 || XR-FRAME / 有点寡淡,加上图像

开始 | 微信开放文档 文档导览 - XR-FRAME / 有点寡淡&#xff0c;加上图像 。 文档导览&#xff0c;知识点整理。 加入纹理 &#xff1a; 新学习标签&#xff1a; <xr-assets bind:progress"handleAssetsProgress" bind:loaded"handleAssetsLoaded…

TS编译选项——编译TS文件同时对JS文件进行编译

一、允许对JS文件进行编译 我们在默认情况下编译TS项目时是不能编译js文件的&#xff0c;如下图中的hello.js文件并未编译到dist目录下&#xff08;这里配置了编译文件放到dist目录下&#xff09; 如果我们想要实现编译TS文件同时对JS文件进行编译&#xff0c;就需要在tsconfi…

GIS基础教程之坐标系

本教程从以下几个方面入手&#xff1a; 坐标系的基本概念 地理坐标系 投影坐标系 如何选择坐标系 根据研究区域大小 根据研究目的&#xff08;等角&#xff1f;等面积&#xff1f;等距离&#xff1f;其他&#xff09; 推荐一个在线坐标系选择网站 GIS坐标系几种情况 数…

【dbeaver】win环境的kerberos认证和Clouders集群中Kerberos认证使用Dbeaver连接Hive和Phoenix

一、下载驱动 cloudera官网 1.1 官网页面下载 下载页面 的Database Drivers 挑选比较新的版本即可。 1.2 集群下载 Hive可能集群没有驱动包。驱动包名称&#xff1a;HiveJDBC42.jar。41结尾的包也可以使用的。注意Jar包的大小一定是十几MB的。几百KB的是thin包不可用。 …

nginx(七十九)nginx与tls/ssl续

一 nginx与tls/ssl续 说明&#xff1a; 本文是基于tls/ssl学习之后,对之前所写tls/ssl博客的补充,重复的不再啰嗦curve: [椭圆] 曲线补充&#xff1a; 会不定期的补充教育&#xff1a; 解决问题为出发点,不要停留在理论上​遗留&#xff1a; wiresahrk分析TLS 1.2 1.3 握手各…

win11系统固定到快速访问的文件夹无法调整顺序的问题

最近在使用win11系统时&#xff0c;固定到快速访问的文件夹无法调整顺序。网上搜了一大圈没有对应的解决方法&#xff0c;柳暗花明&#xff0c;在博主yin0hao的一篇文章中找到了类似的&#xff0c;跟着做了一下&#xff0c;结果问题也解决了。在此记录。 在文件资源管理器地址…

关于10万并发压测时弹性扩容失效问题回答

之前压测过2万用户在30秒内每个用户每秒5次请求&#xff0c;OPS大概在3千左右&#xff0c;但是弹性伸缩虽然在扩容预期值的时候很给力&#xff0c;也能将新加的服务器添加到负载均衡中&#xff0c;但是当cpu使用率超过80%的时候&#xff0c;我其实是有配置报警任务的&#xff0…

MySQL:基础操作(1)

下载配置mysql MySQL&#xff1a;码包安装mysql&#xff08;5.6.51&#xff09;_鲍海超-GNUBHCkalitarro的博客-CSDN博客https://blog.csdn.net/w14768855/article/details/133186897?spm1001.2014.3001.5501 初始登录MySQL mysql -u 用户名 [-p] 一开始什么都没设置 mysql…