首页 > 编程语言 >C/C++结构体最详细的讲解

C/C++结构体最详细的讲解

时间:2024-03-08 17:01:45浏览次数:25  
标签:short struct Student long char C++ 详细 讲解 结构

转载自知乎:https://zhuanlan.zhihu.com/p/611772031

1.定义结构体

法一(推荐,写法简单)

struct Student{
 string m_Name;
 int m_Age;
 Student()=default;
 Student(string name,int age):m_Name(name),age(m_Age){}
};

一般定义结构体和类时,如果不写关于构造函数的任何东西,结构体和类会生成默认构造函数。所以在定义结构体时,不写有参构造函数,系统会为结构体自动生成默认构造函数,这样可以直接定义结构体变量并可以不进行初始化,但是如果在定义结构体时写了有参构造函数,有参构造函数会覆盖默认构造函数,那样在定义结构体变量时,就必须对结构体变量进行初始化。

如果结构体中写了有参构造函数,还想要在不进行变量初始化的情况下定义一个结构体变量,那么需要在结构体中显式声明默认构造函数(结构体名()=default;)。

写结构体的默认构造函数的优势在于可以创建结构体变量时不进行变量的初始化,写有参构造函数可以在创建结构体变量时只初始化结构体的部分参数。

声明结构体变量 struct Student stu{“ybc”,26}; struct可写可不写

访问结构体成员变量 stu.m_Name;

法二

struct Student{
 string m_Name;
 int m_Age; 
 Student()=default;
 Student(string name,int age):m_Name(name),age(m_Age){}
}stu;

stu是一个变量,可以直接访问m_Name,如stu.m_Name;

如果以后不再定义结构体Student的变量,可以省略Student,写成

struct{
 string m_Name;
 int m_Age; 
}stu;

stu同样是结构体的变量,缺点不可以写结构体的构造函数了 wuwu~

法三(推荐)

typedf struct Student{
 string m_Name;
 int m_Age;
 Student()=default;
 Student(string name,int age):m_Name(name),age(m_Age){} 
}stu;

stu是一个结构体类型,stu=struct Student

因为typedef经常用于给数据类型起别名,可以理解为

typedef struct Student stu; stu就成为了struct Student的别名,可以与struct Student执行相同的操作。

使用stu方式,

stu Stu{“ybc”,26};
Stu.m_Name;

2.结构体内存对齐

下面声明三个具有相同数据成员但成员变量的排列顺序不同的结构体 char_short_long、long_short_char和char_long_short。

//声明结构体char_short_long
struct 
{
char c;
short s;
long l;
}char_short_long;
//声明结构体long_short_char
struct
{
long l;
short s;
char c;
}long_short_char;
//声明结构体char_long_short
struct 
{
char c;
long l;
short s;
}char_long_short;

在32位机中,char占1个字节,short占2个字节,long占4个字节。

通过执行程序可知,结构体char_short_long占8个字节,结构体long_short_char占8个字节,结构体char_long_short占12个字节

我们注意到,1 byte (char)+ 2 bytes (short)+ 4 bytes (long) = 7 bytes,既不是8 bytes,也不是12bytes。

所以,结构体成员变量的放置顺序影响着结构体所占的内存空间的大小。一个结构体变量所占内存的大小不一定等于其成员变量所占空间之和。如果一个用户程序或者操作系统(比如uC/OS-II)中存在大量结构体变量时,这种内存占用必须要进行优化,也就是说,结构体内部成员变量的排列次序是有讲究的。

结构体成员变量到底是如何存放的呢?

在没有#pragma pack宏的情况下:

  1. 原则1 结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
  2. 原则2 结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
  3. 原则3 结构体作为成员时,结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素时,那么b应该从8的整数倍地址处开始存储,因为sizeof(double) = 8 bytes)

解析下char_long_short为什么占12个字节

结构体的内存分布如下图所示

结构体char_long_short 内存分布图

首先,1244972能被1整除,所以char_long_short.c放在1244972处没有问题(其实,就char型成员变量自身来说,其放在任何地址单元处都没有问题),根据原则1,在之后的1244973~1244975中都没有能被4(因为sizeof(long)=4bytes)整除的,1244976能被4整除,所以char_long_short.l应该放在1244976处,那么同理,最后一个.s(sizeof(short)=2 bytes)是应该放在1244980处。

是不是这样就结束了?不是,还有原则2。根据原则2的要求,char_long_short这个结构体所占的空间大小应该是其占内存空间最大的成员变量的大小的整数倍。如果我们到此就结束了,那么char_long_short所占的内存空间是1244972~1244981共计10bytes,不符合原则2,所以,必须在最后补齐2个 bytes(1244982~1244983)。

至此,一个结构体的内存布局完成了。

3.联合/联合体(union)

union的定义方式与结构体类似,参考结构体即可。

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和(结构体存在内存对齐问题),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

 

 

标签:short,struct,Student,long,char,C++,详细,讲解,结构
From: https://www.cnblogs.com/hazy-star/p/18061389

相关文章

  • c++多线程
    1.线程库的使用创建进程#include<iostream>#include<thread>//线程库头文件usingnamespacestd;voidthread_1(){cout<<"子线程1"<<endl;}intthread_2(intx){cout<<"子线程2"<<endl;returnx;}intm......
  • C++中的static关键字
    在C++中,static是一个关键字,用于声明静态变量、静态函数、静态类成员以及静态局部变量。static关键字的作用取决于它所修饰的上下文,以下是static关键字的几种常见用法:静态变量:在函数内部使用static关键字声明的变量称为静态局部变量。静态局部变量的生命周期延长到整个程......
  • C++中OpenCV、Armadillo矩阵数据格式的转换方式
      本文介绍在C++语言中,矩阵库Armadillo的mat、vec格式数据与计算机视觉库OpenCV的Mat格式数据相互转换的方法。  在C++语言的矩阵库Armadillo与计算机视觉库OpenCV中,都有矩阵格式的数据类型;而这两个库在运行能力方面各有千秋,因此实际应用过程中,难免会遇到需要将二者的矩阵格......
  • C++中的volatile关键字
    在C++中,volatile是一个关键字,用于告诉编译器,该变量的值可能会在未知的时刻被意外地改变,因此编译器对于该修饰的变量的操作时应该保持对该变量内存地址的直接内存访问操作,而不应对访问该变量的代码进行任何优化。。volatile关键字的主要作用是告诉编译器不要对该变量进行优化,......
  • C++ Qt开发:QFileSystemModel文件管理组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QFileSystemModel组件实现文件管理器功能。QFileSystemModel是Qt框架中的一个关键类,用于......
  • 复试C++ 异常 看程序写结果
    就算每一个case后面都没有break,throw相当于起了break的作用?#include<iostream>#include<stdexcept>usingnamespacestd;classErrorA:publicruntime_error{public:ErrorA():runtime_error{"errorAAAA"}{}};classErrorB:publicruntime_erro......
  • C++入门编程----C++运算符(8)
    什么是运算符运算符是让程序执行特定的数学或逻辑操作的符号,用来表示针对数据的特定操作,也称之为操作符。C++运算符分别有算术运算符、关系运算符、逻辑运算符、赋值运算符、位运算符、移位运算符、sizeof运算符、三目运算符、逗号运算符和域解析运算符。算术运算符C++中的算术......
  • c++ lambda表达式
    引入lambda表达式也有人称之为匿名函数,能够在任何作用域下快速定义一个函数下面这行代码就是一个最简单的lambda表达式,最后输出为3autof=[](intx,inty)->int{returnx+y;};cout<<f(1,2);我们来解析一下lambda表达式autof=[](intx,inty)->int{returnx+y;};......
  • C++保证线程安全的方式
    1、互斥量可以确保同一时间只有一个线程访问临界区,防止出现竞态条件。2、原子操作std::atomic<int>mutex(1);对原子变量的操作是线程安全的。3、读写锁std::shared_mutexmutex;//读者:共享锁定mutex.lock_shared();mutex.unlock_shared();//写者:独占锁定mutex.lock......
  • c/c++指针中 * 和 & 的区别与联系
    在C语言中,*和&是两个非常基础但功能相反的操作符,它们分别是解引用(dereference)操作符和取地址(address-of)操作符。&(取地址操作符)用途:&操作符用来获取变量的内存地址。示例:假设有一个整型变量intx=10;,则&x表示获取变量x的内存地址。如果你有一个指针变量想要存储变量x的地址,可......