【C语言】结构体内存对齐

目录

引入结构体 

 结构的声明

创建和初始化

 内部元素的使用;

特殊声明:

结构体在内存中的对齐

练习: 



引入结构体 

        C语言有各种数据类型,我们已经对一些数据类型很熟悉:

  1. 整型(int)- 存储整数值,包括有符号和无符号两种类型。

  2. 浮点型(float、double、long double)- 存储实数值,包括单精度(float)、双精度(double)和长双精度(long double)三种类型。

  3. 字符型(char)- 存储单个字符,包括有符号和无符号两种类型。

  4. 指针类型(pointer)- 存储内存地址,可以指向其他数据类型。

         但是,仅仅有这些类型是无法描述一些对象的特征的,比如:一个人的多个信息,一个家庭的多个成员等等,那么这时候,就要用到结构体类型来描述一个比较复杂的对象。

        结构体类型就像其他简单数据类型(int,float,double)一样,也是一种数据类型,但是它比较复杂,可以包含多个 简单的数据类型, 这些被包含的数据类型可以是不同的类型。

 

         总之,结构体是为了描述复杂对象而引入的一种新的数据类型。

 结构的声明

        C语言中,结构体(struct)是一种自定义的数据类型,可以将不同的数据类型组合在一起形成一个 新的 数据类型。结构体的定义格式如下:

struct 结构体名称
{数据类型1 成员变量1;数据类型2 成员变量2;...
} 创建的同类型结构体名称;

         有了结构体类型,我们就可以描述复杂对象的特征。例如,要描述一个家庭的成员的信息,可以:

        创建结构体类型Person——包含变量字符串型name, 整型age, 双精度浮点型heignt;

        创建结构体类型Family——包含结构体类型Person, 字符串型location;

 代码如下:

​//声明Person结构体类型struct Person {char name[20];int age;double height;
};//声明Family结构体类型struct Family
{struct Person;char location[10];
}Family_of_my;​

从上述代码可以得出:

        结构体名称 根据具体的实际意义来决定。

        成员变量可以有多个,每个成员变量的数据类型可以是任意数据类型,包括简单数据类型和复杂数据类型。也就是说,一个结构体内部可以再嵌套包含一个结构体类型。

 

        总结,结构体内部的数据类型多样,可以是简单类型,也可以是复杂类型。

 

创建和初始化

        结构体的初始化可以按照不同方式进行:

        1.按照结构体内部元素顺序

        2.按照指定顺序

#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号};int main()
{//按照结构体成员的顺序初始化struct Stu s = { "张三", 20, "男", "20230818001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的顺序初始化struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "⼥printf("name: %s\n", s2.name);printf("age : %d\n", s2.age);printf("sex : %s\n", s2.sex);printf("id : %s\n", s2.id);return 0;}

        总结, 初始化可以按照正常顺序,还可按照指定顺序。

 内部元素的使用;

        要用到结构体操作符。 

​
​
#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号};int main()
{//按照结构体成员的顺序初始化struct Stu s = { "张三", 20, "男", "20230818001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的顺序初始化struct Stu* s2 = &s;printf("name: %s\n", s2->name);printf("age : %d\n", s2->age);printf("sex : %s\n", s2->sex);printf("id : %s\n", s2->id);return 0;}​​

 

         总结,要使用结构体内部元素,要用到结构体操作符:

.  和 ->

用例:

结构体.成员名

结构体指针->成员名

特殊声明:

        在声明结构的时候,可以不完全的声明。也就是,可以省略结构体的标签。

例如:

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

        但是,这两个匿名的类型完全一致的结构体是同一个结构体类型吗?

也就是说:

p = &x;

        这段代码合法吗?

        经过测试,编译器会把上面的两个声明当成完全不同的两个类型,所以是⾮法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。
 

 

结构体在内存中的对齐

        现在,我们已经对结构体有了一个基本的认识,那么,结构体的大小是如何计算的呢?


 

        我们先看一个实例:

计算下列两个结构体的大小:


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

        我们可以先猜测:

        既然两个结构体内部的变量类型和数目完全一致,那么我们有理由猜测两个结构体大小相同,但是,实际情况并不是这样:

 

        其实,结构体在内存中的存储有一套自己的规则:

 首先,引入一个概念:

        对齐数

        对齐数=编译器默认的⼀个对齐数   和 该成员变量长度的较小值

        默认对齐数 :

VS 中默认的值为 8 


Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

结构体的基本对齐方法是:

        1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
        2.其他成员变量要对齐到对齐数的整数倍的地址处

结构体大小的计算:


        1.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。


        2.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

 

        这样一来,我们分析上两个问题:


 

        对于s1,先放入char类型,由于char类型是1个字节,小于8(VS默认值),所以直接放在0地址处。

        值得一提,长度是1的char无论何时都不会浪费空间,它会直接顶着上一个数据的存储空间放置。

        int型,大小4字节,小于8(VS默认值),所以放在sizeof(int)的整数倍的地址处,也就是4开始,到7结束。

        char 紧跟着int型;


        由于最大对齐数是4,此时结构体的最小大小大于8,要满足4的整数倍,那么这个结构体的大小向上取 是12。

        对于s2 :

        放入两个char,一个int后的结构体最小大小正好是8,那么结构体总大小就是8。

 

 


练习: 

int main(int argc, char* argv[])
{struct tagTest1{short a;char d; long b;   long c;   };struct tagTest2{long b;   short c;char d;long a;   };struct tagTest3{short c;long b;char d;   long a;   };struct tagTest1 stT1;struct tagTest2 stT2;struct tagTest3 stT3;printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3));return 0;

        结果: 


 完~

未经作者同意禁止转载

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MAC IDEA Maven Springboot

在mac中&#xff0c;使用idea进行maven项目构建 环境配置如何运行maven项目1.直接在IDEA中运行2.使用jar打包后执行 如何搭建spring boot1.添加依赖2.创建入口类3.创建控制器4. 运行5.其他 环境配置 官网安装IDEA使用IDEA的创建新项目选择创建MAEVEN项目测试IDEA的MAVEN路径是…

Mybatis-plus介绍与入门

前言 MyBatis-Plus是在MyBatis基础上的一个增强工具库&#xff0c;旨在简化开发者的工作&#xff0c;提高开发效率&#xff0c;同时保留MyBatis的灵活性。使用 MyBatis-Plus 可以减少重复性的代码&#xff0c;简化常见的数据库操作 官方学习文档&#xff1a;MyBatis-Plus (bao…

phpstudy是什么?

PHPStudy 是一个集成环境工具&#xff0c;它将 PHP 开发所需的软件&#xff0c;如 Apache&#xff08;Web服务器&#xff09;、MySQL&#xff08;数据库服务器&#xff09;、PHP&#xff08;脚本语言&#xff09;等打包在一起&#xff0c;以便用户能够轻松安装和配置这些软件&a…

fl studio20中文内测版下载2024最新完美实现汉化

fl studio20是一款众所周知的水果编曲软件&#xff0c;能够剪辑、混音、录音&#xff0c;它的矢量界面能更好用在4K、5K甚至8K显示器上&#xff0c;还可以可以编曲、剪辑、录音、混音&#xff0c;让你的计算机成为全功能录音室&#xff0c;不论是在功能上面还是用户界面上都是数…

为了吃鸡苦练狙击,避免坑队友自己造一个狙击游戏!

引言 一文教会你造一个简易的狙击游戏。 说到狙击&#xff0c;相信大家都不陌生&#xff0c;无论是影视作品还是网络游戏&#xff0c;都经常能看到狙击枪的身影&#xff0c;最深刻的是它能够从百里之外&#xff0c;一枪爆头。 本文将介绍如何在Cocos Creator中造一个简易的狙…

真正可行的vue3迁移到nuxt3方法(本人亲测,完全避坑)

终于到了总结经验的时候了&#xff0c;这绝对是全网唯一、完全真正可行的干货。 在我看来&#xff0c;知识就是要拿来分享的&#xff0c;分享给他人也是在提高自己。我绝对不会搞什么订阅或者vip专栏来搞钱坑害各位&#xff0c; 因为我在csdn写文章最主要的目的是为了记录和总…

虚幻学习笔记13—C++静态和动态加载

一、前言 我们在蓝图中可以很方便的添加各种需要的组件&#xff0c;那么在C代码中要如何实现呢。在代码中分静态和动态加载&#xff0c;而无论静态和动态&#xff0c;加载的内容有资源和资源类&#xff0c;资源类通常为带资源的蓝图类。 二、实现 在实现静态或动态加载时&…

科技云报道:从数据到生成式AI,是该重新思考风险的时候了

科技云报道原创。 OpenAI“宫斗”大戏即将尘埃落定。 自首席执行官Sam Altman突然被董事会宣布遭解雇、董事长兼总裁Greg Brockman辞职&#xff1b;紧接着OpenAI员工以辞职威胁董事会要求Altman回归&#xff1b;再到OpenAI董事会更换成员、Altman回归OpenAI。 表面上看&…

OpenHarmony关于修改系统横屏导致启动视频显示不全问题解决

前言 OpenHarmony源码版本&#xff1a;4.0release 开发板&#xff1a;DAYU / rk3568 前段时间写的设置OpenHarmony启动视频&#xff0c;在竖屏状态下是正常的&#xff0c;但是横屏状态下显示不全。 链接直达&#xff1a;OpenHarmony 设备启动Logo和启动视频替换指南-CSDN博…

Java EE 多线程之线程安全的集合类

文章目录 1. 多线程环境使用 ArrayList1. 1 Collections.synchronizedList(new ArrayList)1.2 CopyOnWriteArrayList 2. 多线程环境使用队列2.1 ArrayBlockingQueue2.2 LinkedBlockingQueue2.3 PriorityBlockingQueue2.4 TransferQueue 3. 多线程环境使用哈希表3.1 Hashtable3.…

优雅玩转实验室服务器(一)登录服务器

这篇文章更加偏向于使用python程序进行研究的朋友们 原料 Windows主机实验室Linux服务器&#xff08;可以访问互联网&#xff09;一点点耐心 step.0 windows terminal is all you need 别跟我说什么putty&#xff0c;什么winscp&#xff0c;我就是单推Win11自带的软件——win…

深度学习在人体动作识别领域的应用:开源工具、数据集资源及趋动云GPU算力不可或缺

人体动作识别检测是一种通过使用计算机视觉和深度学习技术&#xff0c;对人体姿态和动作进行实时监测和分析的技术。该技术旨在从图像或视频中提取有关人体姿态、动作和行为的信息&#xff0c;以便更深入地识别和理解人的活动。 人体动作识别检测的基本步骤包括&#xff1a; 数…

[已解决】uniapp内置插件,editor富文本报错(附quill.min.js、image-resize.min.js文件)

在使用uni-app运行内置插件editor时&#xff0c;无法输入内容&#xff0c;控制台报错 原因&#xff1a;查看官网得知&#xff0c;需动态引入quill.min.js、image-resize.min.js文件 解决方法&#xff1a; 1.下载quill.min.js、image-resize.min.js到项目static/eidtor文件中 链…

2024生化仪器与实验室装备创新发展论坛将于3月6日济南召开

2024生化仪器与实验室装备创新发展论坛 2024年3月6日 | 山东国际会展中心 一、会议介绍 近年来&#xff0c;制药及生物制药行业的高速成长&#xff0c;生化仪器与实验室装备作为科学研究的重要组成部分&#xff0c;同时也在不断的更新和升级。伴随生物制药、CRO等下游行业的…

js 数组 slice() 浅拷贝与sort()数组的排序

slice() slice()方法将从数组中浅拷贝指定开始位置和结束位置之间的数组元素到一个新的数组&#xff0c;并返回新数组。 结束位置不在浅拷贝的范围 [1, 2, 3, 4, 5].slice(2&#xff0c;3); 结果时 3 从数组第二位开始拷贝 &#xff0c;到第三位为止 注意返回内容是一个数…

超燃超欢乐!修仙喜剧动画《师兄啊师兄》第二季稳健开播

12月14日&#xff0c;备受瞩目的《师兄啊师兄》第二季终于稳健开播&#xff01;首播两集连放&#xff0c;同时第一季全13集限免&#xff0c;不仅便于新观众丝滑入坑&#xff0c;老观众也可以二刷重温&#xff0c;可以说是非常良心了&#xff01; 《师兄啊师兄》改编自人气网络小…

【云原生kubernets】Pod详解

一、Pod介绍 1.1.概念 Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的&#xff0c;例如&#xff0c;用于管理Pod运行的State…

将 Github token 添加至远程仓库

将 Github token 添加至远程仓库后便于每次 push 重复输入的麻烦 首先,将已生成的 token 记录(注:生成后的 token 确认后便无法查看只能重新生成)并找到对应的项目 git 本地文件路径下 其次,将其与项目所关联,按如下格式配置即可 token 格式类似于 ghp_CAxxxxxxxxxxxxxxxxxGx5j…

【rabbitMQ】rabbitMQ控制台模拟收发消息

目录 1.新建队列 2.交换机绑定队列 3.查看消息是否到达队列 总结&#xff1a; 1.新建队列 2.交换机绑定队列 点击amq.fonout 3.查看消息是否到达队列 总结&#xff1a; 生产者&#xff08;publisher&#xff09;发送消息&#xff0c;先到达交换机&#xff0c;再到队列&…

微软Microsoft二面面试题分享通过总结(不是标准答案分享

误打误撞 我写的shitty代码 当年面试算法开发岗竟然通过了 Background 先说下背景&#xff0c;软件工程本科毕业之后&#xff0c;当年8月到北欧读两年制硕士。面试发生在当年的11月&#xff0c;微软哥本哈根&#xff0c;location在丹麦的哥本哈根lingby&#xff08;是不是这么…