C/C++结构体内存对齐的一些思考

在C++中,结构体的内存对齐是为了提高访问结构体成员变量的效率和保证硬件的要求

结构体对齐 C/C++

  • C++ 结构体内存对齐的示例代码
  • C/C++结构体`内存对齐的原则`
  • 结合汇编代码分析结构体的内存对齐问题


C++ 结构体内存对齐的示例代码

#include <iostream>struct Test_Struct {char c;int i;double d;
};int main() {std::cout << "Size of Test_Struct: " << sizeof(Test_Struct) << " bytes" << std::endl;return 0;
}

运行结果:
在这里插入图片描述


C/C++结构体内存对齐的原则

这里直接给出原则如下:

  • 数据成员按照声明顺序依次排列每个数据成员都会占用相应的内存空间
  • 结构体的大小是其数据成员大小的总和,但并不等于所有数据成员大小之和
  • 数据成员的对齐要求是根据它们的类型而定。通常,基本类型(如int、char、double等)的对齐要求是其自身大小或操作系统的最小字节对齐数中较小的那个
  • 如果结构体的某个数据成员的大小超过了默认的对齐要求,那么编译器会进行填充以满足对齐要求,从而保证结构体整体的对齐。
  • 编译器可能会在结构体的末尾添加额外的填充字节,以保证结构体的整体对齐。
  • 可以使用C++中的sizeof关键字来获取一个结构体的大小,它所返回的值即为该结构体的字节大小。

需要注意的是,结构体的内存对齐问题在不同的编译器和平台上可能会有所差异,可以使用预处理指令#pragma pack或编译选项来修改默认的内存对齐方式。为了保证代码的可移植性,可以使用固定大小的数据类型(例如uint32_t、int64_t等)来代替原生类型,以确保在不同平台上具有相同的内存布局和对齐方式。


结合汇编代码分析结构体的内存对齐问题

利用compiler explorer在线查看代码的汇编形式,汇编代码如下:

.LC0:.string "Size of MyStruct: "
.LC1:.string " bytes"
main:push    rbpmov     rbp, rspmov     esi, OFFSET FLAT:.LC0mov     edi, OFFSET FLAT:_ZSt4coutcall    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)mov     esi, 16mov     rdi, raxcall    std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned long)mov     esi, OFFSET FLAT:.LC1mov     rdi, raxcall    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)mov     esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_mov     rdi, raxcall    std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))mov     eax, 0pop     rbpret

首先在数据段部分,.LC0和.LC1,存储了输入和输出的字符串内容,这个没什么可解释的(C/C++数据段主要是用来保存全局变量和静态变量的内存区域,此外还有文本段、栈Stack、堆Heap、常量存储区constant storage area)。

其次,push rbp保存调用者的栈帧指针,mov rbp, rsp将当前栈指针(rsp)赋值给基指针(rbp),建立新的栈帧;mov esi, OFFSET FLAT:.LC0将字符串.LC0的地址保存到寄存器esi中。

mov edi, OFFSET FLAT:_ZSt4cout将全局对象 _ZSt4cout 的地址保存到寄存器edi中。

mov esi, 16将常数值16保存到寄存器esi中,即结构体的大小。

mov rdi, rax将输出操作符结果的返回值保存到寄存器rdi中,作为下一次输出操作的目标。

mov esi, OFFSET FLAT:.LC1 将字符串.LC1的地址保存到寄存器esi中。

mov rdi, rax 将上一次输出的返回值保存到寄存器rdi中,作为下一次输出的输出流对象。

最后,将eax寄存器的值设置为0:mov eax, 0;弹出栈中的rbp值:pop rbp;返回到调用函数的地址:ret

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

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

相关文章

C++之GNU C的__attribute__常用属性(一百五十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Symbol.for()

示例&#xff1a;Symbol() 和 Symbol.for(‘ ’)的区别 Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中&#xff0c;键为 "foo" Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbolSymbol.for("b…

ISE软件基本使用

ISE软件基本使用 基本设置 关联notepad的操作&#xff1a;选择notepad的exe文件路径&#xff0c;并且加 { } 符号&#xff0c;并在结尾加$1。ISE可以设置程序运行的速度等级&#xff0c;该速度等级会影响程序从外部SPI Flash启动的启动速度。JTAG 接口的作用是将编译好的程 序…

Docker中安装Nginx

查看可以安装的Nginx版本: docker search nginx 下载最新版本: docker pull nginx :latest 可以省略 运行容器: docker run -itd --name my_nginx -p 80:80 nginx 在主机通过 https://localhost:80或者 http://192.168.40.100:80可以访问 如果之前创…

java feign的使用详细步骤及okhttp的使用

1、首先创建一个feign的模块并配置依赖&#xff0c;如图&#xff1a; 1、引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency&g…

基于java的汽车服务管理系统(Car Service Management System)

设计一款基于java的管理和跟踪对车辆所做服务的系统。我们的系统允许服务技术人员跟踪客户、他们的车辆以及对这些车辆所做的服务。 需要项目的朋友私信我&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; Car Service Management System 基本的使用…

Python 字符串的使用

字符串使用 1. 字符串的定义方式 双引号或者单引号括起来的数据&#xff0c;就是字符串。使用三引号括起来也是字符串&#xff0c;并支持换行。 例&#xff1a; # 使用反斜线 对单引号进行转义 name1 i\ Tom name2 "Rose" name3 Tom name4 ""&qu…

K8s是什么?

K8s是开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用。&#xff08;docker只能是单主机上的容器化的应用&#xff09; 职责&#xff1a;管理容器应用 目标&#xff1a;让部署容器化的应用简单高效 Rancher 可以通过界面管理 K8s 平台 一、让我们先来了解一个什…

Jenkins+Docker 实现一键自动化部署项目

1、环境配置 环境&#xff1a;centos7git(gitee) 简述实现步骤&#xff1a;在docker安装jenkins&#xff0c;配置jenkins基本信息&#xff0c;利用Dockerfile和shell脚本实现项目自动拉取打包并运行。 2、安装docker docker 安装社区版本CE 确保 yum 包更新到最新。 yum …

ESP32设备驱动-SCD40二氧化碳湿度和温度传感器驱动

SCD40二氧化碳湿度和温度传感器驱动 文章目录 SCD40二氧化碳湿度和温度传感器驱动1、SCD40介绍2、硬件准备3、软件准备4、驱动实现1、SCD40介绍 SCD4x 是 Sensirion 的下一代微型 CO2 传感器。 该传感器基于光声 NDIR 传感原理和 Sensirion 的专利 PASens 和 CMOSens 技术,以…

联想小新电脑无法启动怎么办?

1&#xff0c;电脑启动不了 2&#xff0c;强制断电3次开机后&#xff0c;Win11进入高级启动模式 &#xff08;注意每次强制关机要按住15秒左右&#xff09; 3&#xff0c;选择疑难解答 4&#xff0c;选择高级选项 5&#xff0c;卸载更新 6&#xff0c;卸载最新的质量更新 7&am…

代理模式(Proxy)

定义 代理是一种结构型设计模式&#xff0c;让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问&#xff0c;并允许在将请求提交给对象前后进行一些处理。 前言 1. 问题 举个例子&#xff1a;有这样一个消耗大量系统资源的巨型对象&#xff0c; 你只是偶尔需…