首页 > 系统相关 >C++结构体内幕揭秘:sizeof之谜与内存布局探秘

C++结构体内幕揭秘:sizeof之谜与内存布局探秘

时间:2024-03-23 09:23:10浏览次数:17  
标签:字节 填充 示例 C++ 对齐 sizeof 探秘 结构

 

概述:C++结构体的`sizeof`不总是等于每个成员的`sizeof`之和,因为对齐和填充影响了内存布局。未对齐的结构体可能存在间隙,而对齐的结构体会插入填充以保持对齐。通过示例展示了结构体的内存对齐和填充,以及如何使用模板元编程打印结构体成员的偏移量,深入理解内存布局。

在C++中,结构体的sizeof并不总是等于每个成员的sizeof之和,这是由于对齐和填充的影响。编译器为了提高内存访问速度,通常会在结构体成员之间插入一些填充字节以对齐数据。

基础功能:

示例源代码:

#include <iostream>

// 未进行对齐的结构体
struct WithoutPadding {
    char a;    // 1 字节
    int b;     // 4 字节
    char c;    // 1 字节
};

// 进行对齐的结构体
struct WithPadding {
    char a;    // 1 字节
    char padding[3];  // 对齐填充 3 字节
    int b;     // 4 字节
    char c;    // 1 字节
};

int main() {
    std::cout << "WithoutPadding 大小:" << sizeof(WithoutPadding) << std::endl;
    std::cout << "WithPadding 大小:" << sizeof(WithPadding) << std::endl;

    return 0;
}

在这个示例中,WithoutPadding 结构体的大小是 6 字节(1 + 4 + 1),而WithPadding 结构体的大小是 12 字节(1 + 3(填充)+ 4 + 1)。这是因为编译器为了对齐int类型的成员b,在其前面插入了3字节的填充。

高级功能:

示例源代码:

#include <iostream>
#include <type_traits>

template <typename T>
void PrintOffsets() {
    std::cout << "Offsets for " << typeid(T).name() << ":" << std::endl;

    size_t offset = 0;
    size_t size = sizeof(T);

    // 使用模板元编程逐个打印成员的偏移量
    // 对于 C++17,可以使用 std::is_standard_layout<T> 确保是标准布局类型
    if constexpr (std::is_standard_layout<T>::value) {
        while (offset < size) {
            std::cout << "  Offset of member at index " << offset << ": " << offsetof(T, offset) << std::endl;
            offset++;
        }
    } else {
        std::cout << "  Not a standard layout type." << std::endl;
    }

    std::cout << std::endl;
}

struct ExampleStruct {
    char a;    // 1 字节
    int b;     // 4 字节
    char c;    // 1 字节
};

int main() {
    PrintOffsets<ExampleStruct>();

    return 0;
}

在这个示例中,PrintOffsets 函数使用模板元编程逐个打印结构体成员的偏移量。ExampleStruct 结构体包含了对齐填充,通过offsetof宏可以获取每个成员的偏移量。这有助于理解结构体内存布局的细节。

通过这两个示例,展示了结构体大小不等于成员sizeof之和的原因,以及如何使用模板元编程逐个打印结构体成员的偏移量。这些知识有助于理解内存对齐和结构体内存布局。

 

标签:字节,填充,示例,C++,对齐,sizeof,探秘,结构
From: https://www.cnblogs.com/hanbing81868164/p/18090780

相关文章

  • 2024届 C++ 刷题 笔试强训 Day 04
    选择题01有以下程序#include<iostream>#include<cstdio>usingnamespacestd;intmain(){intm=0123,n=123;printf("%o%o\n",m,n);return0;}程序运行后的输出结果是()A01230173B0123173C123173D173173题目解析:intm=......
  • 深入理解 C++ 语法:从基础知识到高级应用
    C++语法让我们将以下代码分解以更好地理解它:示例#include<iostream>usingnamespacestd;intmain(){cout<<"HelloWorld!";return0;}示例解释第1行:#include<iostream>是一个头文件库,它让我们可以使用输入和输出对象,比如cout(在第5行使用)。头文件为......
  • C++中const小结
    const修饰普通变量表示变量的值不能被改变。下面两条语句(第2行和第3行)表示的意思一致。inta;constintca=42;//intconstca=42;const修饰指针指向常量的指针不能改变其指对象的值。第5行代码是错误的。inta=42;constint*ip=&a;intconst*ipp=......
  • [c++/gcc] Centos 7.9升级 gcc 4.8.5 到 gcc11 [转]
    0序本文背景:因在centos7.9server上安装nodejs21.7.1,编译nodejs时,依赖了gnu17/gcc11。例如:遇到Qtrequiresc++11support、-std=gnu++17例如:编译器不支持c++17,就会提示:g++:error:unrecognizedcommandlineoption‘-std=c++17’例如:编译器不支持c++17,就会提示:g++:......
  • 【C++ 08】vector 顺序表的常见基本操作
    文章目录前言......
  • 【C++】string类模拟实现
    个人主页:zxctscl如有转载请先通知文章目录1.前言2.构造函数和析构函数3.遍历3.1下标+[]3.2迭代器4.Modifiers4.1`push_back`和`append`4.2+=4.3insert4.4erase4.5swap5.Capacity5.1resize5.2clear6.深浅拷贝6.1浅拷贝(值拷贝)6.2深拷贝7.String......
  • C++暴力指南
    关于暴力做法暴力,非常直白的就是直接硬做,不管他循环有多大,不管他数据量有多大。你要记住的一个事情就是,暴力只面向小数据,但是必定能得到正确解(前提当然是你没写错)甚至你需要进行对拍的时候你也得先写一个暴力出来才能方便对拍。但是也因此,为了尽可能的偷分,暴力里要做尽可能的比......
  • C++流媒体开源库Live555详细介绍
    C++流媒体开源库Live555详细介绍C语言资深大师  5人赞同了该文章1、Live555简介Live555是一个为流媒体提供解决方案的跨平台的C++开源项目,它使用了RTP/RTCP、RTSP、SIP开放标准协议,实现了标准流媒体传输。Live555实现了对多种音视频编码格式的音视频......
  • C++ 指针,指针引用,二级指针作为实参传入函数体,形参改变指向的问题
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录一、形参指向变化,实参指向不变二、指针引用传递改变实参指向三、二级指针**传递改变实参指向一、形参指向变化,实参指向不变前提了解:无论是值传递,指针传递,引用传递,形参和实参都是完全不同的......
  • C++中char,char*,char[],string存储中文的问题
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、使用char,char*,char[],string存储中文二、内存中是乱码,但是可以正常输出三、解决方法:w_char,前言学习时遇到的问题,如有不对,欢迎大佬们批评指正!一、使用char,char*,char[],string存......