C++中sizeof运算符到底怎么用才不踩坑

来源:前端技术作者:深圳网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《C++中sizeof运算符到底怎么用才不踩坑》,敬请观看详情。空类占几个字节、数组名和指针用sizeof结果为何不同、结构体因内存对齐导致大小翻倍,这些细节常让刚接触C++的人困惑。sizeof是编译期运算符,返回对象或类型所占字节数,不涉及运行时计算。它对数组求得是整个数组容量,对指针只是指针本身长度,与指向内容无关。结构体大小受成员顺序和对齐规则影响,并非简单相加。弄清这些规则,才能准确估算内存、避免缓冲区越界和序列化错位。

在C++里,sizeof是一个编译期一元运算符,用来获取类型或对象在内存中占用的字节数。它既不像函数那样有运行时开销,也不关心对象里存了什么值,只根据类型信息在编译阶段算出大小。理解它的计算规则,对内存布局、网络传输和结构体内存优化都十分关键。

一、sizeof的基本语法与常见用法

sizeof有两种写法:一种是跟类型名,必须加括号,例如sizeof(int);另一种是跟表达式或变量,括号可省略,例如sizeof x。因为sizeof是运算符而非函数,所以后面接变量时括号不是语法强制要求,但接类型时不能省。编译器在生成代码前就把它替换成常量整数。

下面代码展示了基础类型的尺寸差异,不同平台结果可能不同,但规律一致:

#include <iostream>

int main() {
    std::cout << "sizeof(char) = " << sizeof(char) << std::endl;
    std::cout << "sizeof(int) = " << sizeof(int) << std::endl;
    std::cout << "sizeof(double) = " << sizeof(double) << std::endl;
    // 表达式形式,括号可省略
    int a = 10;
    std::cout << "sizeof a = " << sizeof a << std::endl;
    return 0;
}

在常见64位Linux环境下,char为1字节,int为4字节,double为8字节。由于sizeof是编译期常量,它还可以用于定义数组长度,例如char buf[sizeof(int) * 4];,这样写能让数组大小跟随类型变化自动调整。

需要注意,对引用类型使用sizeof,得到的是被引用对象的大小,而不是引用本身的实现大小。引用在语言层面只是别名,不额外占用存储概念上的独立空间。

二、数组与指针的sizeof差异

这是最容易出错的地方。当对数组名直接使用sizeof时,得到的是整个数组的字节数;而当数组退化为指针后,sizeof只能得到指针本身的大小。很多初学者误以为传参后sizeof还能算出数组长度,结果引发逻辑错误。

看下面示例,同样叫arr,在main里和函数参数里表现完全不同:

#include <iostream>

void printSize(int arr[]) {
    // 此处arr已退化为指针
    std::cout << "in func sizeof(arr) = " << sizeof(arr) << std::endl;
}

int main() {
    int arr[10];
    std::cout << "in main sizeof(arr) = " << sizeof(arr) << std::endl;
    printSize(arr);
    return 0;
}

在64位系统,main中输出40(10乘以4字节),而函数内输出8,因为参数int arr[]等价于int* arr。若想在函数里获知数组元素个数,应额外传入长度,或用模板引用形参保留数组类型信息。

利用模板可以在编译期保留数组维度,例如:

template <typename T, size_t N>
size_t arrayLen(T (&)[N]) {
    return N;
}

这种方式通过引用数组避免退化,N直接由编译器推导,比在函数内用sizeof安全得多。

三、结构体内存对齐对sizeof的影响

结构体的sizeof通常不是成员大小简单相加,编译器会按对齐规则插入填充字节。对齐目的是让CPU更高效地访问数据,不同平台默认对齐值不同,一般按成员中最大基础类型对齐。

观察下面两个成员顺序不同的结构体:

#include <iostream>

struct A {
    char c;
    int i;
    short s;
};

struct B {
    char c;
    short s;
    int i;
};

int main() {
    std::cout << "sizeof(A) = " << sizeof(A) << std::endl;
    std::cout << "sizeof(B) = " << sizeof(B) << std::endl;
    return 0;
}

在默认对齐下,A中char后填3字节让int对齐,short后可能再填2字节凑整,大小常为12;B中char和short共用前4字节,int紧跟其后,大小常为8。可见重排成员能明显压缩空间。

可用#pragma packalignas改变对齐方式,但过分压缩可能降低访问速度,且与外部数据格式交互时要格外小心,避免读写错位。

四、空类与继承下的sizeof

空类对象在C++中大小至少为1字节,目的是让不同对象有唯一地址。若类里有虚函数,会额外增加虚表指针,64位下通常加8字节。继承时,基类子对象也参与布局。

#include <iostream>

class Empty {};
class WithVirtual {
    virtual void foo() {}
};

int main() {
    std::cout << "sizeof(Empty) = " << sizeof(Empty) << std::endl;
    std::cout << "sizeof(WithVirtual) = " << sizeof(WithVirtual) << std::endl;
    return 0;
}

运行后Empty多为1,WithVirtual多为8。当空类作为基类且被派生类继承时,若满足空基类优化条件,派生类不一定要为它分配那1字节,这也是标准鼓励的内存优化手段。

掌握这些sizeof行为,能帮助你在写底层库、序列化协议或内存池时,精确控制对象体积,不至于因误判大小造成溢出或兼容问题。

sizeofC++内存对齐指针大小修改时间:2026-08-06 18:21:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。