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

news/2024/11/17 11:05:18/

在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.ppmy.cn/news/694656.html

相关文章

Jackson图

Jackson图 虽然程序中实际使用的数据结构种类繁多&#xff0c;但是他们的数据元素彼此之间的逻辑关系却只有顺序、选择和重复3类&#xff0c;因此&#xff0c;逻辑数据结构也只有这3类。 1.顺序结构 顺序结构的数据由一个或多个数据元素组成&#xff0c;每个元素按确定次序出…

仿美图秀秀的图片剪切

先贴上美图秀秀原作的效果图&#xff0c;右边是我仿的效果图。 刚一眼打量过去&#xff0c;吸引我们的就是那四个大点。就从它开始吧&#xff0c;目前看来这个大点是一个图片&#xff0c;当点击下去的时候有加亮的效果&#xff0c;可能这又是一张图片。我们先不要考虑这些&…

superset

应用场景 数据进入到数据库中,查询只能看到一行行的数据,最好是可以通过图形的方式将数据形象化的展示出来,通过图形进行组合分析,仪表分析,地图分析,多维分析等等,更加详细的通过图形展示数据,展示规律,展示分析! 操作步骤 # yum install gcc libffi-devel python-d…

Supreme Number

//特别坑 371&#xff0c; 713&#xff0c; 731 都不是素数 /*#include <iostream> #include <math.h> using namespace std; int a[] {1, 2, 3, 5, 7,11, 13, 17, 23, 31, 37, 53, 71, 73, 113, 131, 137, 173, 311, 317, 371, 713, 731}; int isPrime(lon…

SuperSlide图片切换

SuperSlide图片切换 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. /*SuperSlide图片切换*/jQuery(".focusBox").slide({mainCell: ".pic",effect: "fold",a…

在线生成supreme风格图片

原文链接&#xff1a; https://justforuse.github.io/blog/zh-cn/2018/12/supreme-image/ 最近被本山大叔鬼畜洗脑了?&#xff1a;https://www.bilibili.com/video/av19390801?fromsearch&seid2488280777914879673 supreme风格图片也是土潮土潮的&#xff0c;所以就来做…

P4824 [USACO15FEB] Censoring S

请读者在阅读前充分理解KMP与其失配函数的意义。 题目描述 原题来自&#xff1a;USACO 2015 Feb. Silver 给出两个字符串 S 和 T&#xff0c;每次从前往后找到 S 的一个子串 AT 并将其删除&#xff0c;空缺位依次向前补齐&#xff0c;重复上述操作多次&#xff0c;直到 S 串…

Golang:cannot find main module; see ‘go help modules‘解决

出现这个的原因就是之前在Golang语言介绍、环境搭建以及编译工具&#xff08; CDN 加速代理&#xff09;https://mp.csdn.net/mp_blog/creation/editor/131431492 这个部分配置CDN加速代理的时候&#xff0c;开启了GO111MODULEon后&#xff1b; go会忽略GOPATH和vendor文件夹&…