liangbm3's blog

Back

1. sizeof运算符简介#

sizeof是C++中的一个关键字和一元运算符,其作用是取得数据类型或者表达式的大小(以Byte为单位),求得结果的类型是std::size_t。它是一个编译时运算符,在绝大多数情况下是在编译时进行运算(在运行时运算的特例后面会提及)。sizeof运算符的语法有两种形式:

  • 对类型使用:必须使用括号
    sizeof(type)
    cpp
    例如:sizeof(int)sizeof(double)
  • 对表达式使用:括号是可选的
    sizeof expression
    // 或者
    sizeof(expression)
    cpp
    例如:sizeof(x)sizeof(x+1)

2. sizeof运算符的常见用法#

  • sizeof运算符可以求得基本数据类型的大小,例如:

    sizeof(char);//结果为1
    cpp
  • 对变量使用sizeof,可以求得该变量类型的大小,例如:

    int a;
    sizeof a;//结果为4
    cpp
  • 对数组使用sizeof,可以求得整个数组的长度,一个常见的用法是计算数组中元素的数量,例如:

    int arr[] = {1, 2, 3, 4, 5, 6, 7};
    int numElements = sizeof(arr) / sizeof(arr[0]);
    std::cout << "Number of elements: " << numElements << std::endl; // 输出: 7
    cpp
  • 对指针变量使用sizeof,可以求得指针本身的大小。对引用使用sizeof,可以求得被引用对象的大小,而不是引用本身的大小,例如:

    int* p = nullptr;
    sizeof p;//结果为8(64位系统)或4(32位系统)
    
    int x = 10;
    int& ref = x;
    sizeof ref;//结果为4
    cpp
  • 对类或者结构体使用sizeof,可以求得该类或者结构体的一个对象占用的总字节数,通常包括:

    • 非静态成员变量的大小
    • 编译器为了内存对齐而额外添加的字节
    • 如果存在虚函数,会包含一个指向虚函数表的虚指针大小

    不包括:

    • 静态成员变量的大小,因为静态成员变量不属于任何一个对象,而是由所有对象共享
    • 成员函数的大小,因为成员函数存储在代码段,不占用对象的内存空间
    class MyClass {
    public:
        int a;       // 4 bytes
        char b;      // 1 byte
        // 内存对齐机制会填充3 bytes
        double c;    // 8 bytes
        static int s; // 不计入 sizeof
        virtual void func() {} // 会增加一个 vptr 的大小
    };
    
    // 在一个典型的64位系统上,sizeof(MyClass) 可能是 24 字节
    // (vptr: 8) + (int a: 4) + (char b: 1) + (padding: 3) + (double c: 8) = 24
    cpp

    在C++中,由于任何对象都必须有一个唯一地址,因此空类和结构体的大小至少为1字节,例如:

    class Empty {};
    std::cout << "Size of Empty class: " << sizeof(Empty) << std::endl; // 输出: 1
    cpp

3. sizeof运算符的一些特性#

  • sizeof是运算符而不是函数,这是sizeof最基本的特性。因此我们通常不会采用参数和返回值的说法。
  • sizeof不能求得void类型的长度,因为void类型是没有大小的,我们也无法声明void类型的变量。sizeof能够求得void类型的指针的长度,因为void类型的指针是有大小的。
    sizeof(void);//非法
    sizeof(void*)//合法
    cpp
  • 对任何类型的指针变量使用sizeof,得到的永远是指针本身的大小,而不是它所指向的对象或内存块的大小。例如:
    int arr[10];
    int *p = arr;
    std::cout << sizeof(arr) << std::endl; // 输出:10 * sizeof(int) = 40
    std::cout << sizeof(p) << std::endl;   // 输出:指针大小,通常是 4 或 8 字节
    cpp
  • 在函数参数中,数组会退化成指针,因为在函数参数传递时,数组被退化成指针了,例如:
    void func(int arr[10]) 
    {
        std::cout << sizeof(arr) << std::endl; // 实际是 sizeof(int*),而不是数组大小
    }
    int main() {
        int arr[10];
        func(arr);
    }
    cpp
  • 表达式不会被求值,但是会返回表达式计算结果的类型大小。例如:
    int x = 5;
    double y = 5.0;
    std::cout << sizeof(x++) << std::endl; // 结果为4,x 仍然等于 5
    std::cout << sizeof(x+y) << std::endl; //结果为8,求得的是double的大小
    cpp
  • 动态内存只能求得指针大小,无法获取内存块的大小,例如:
    int *p = new int[10];
    std::cout << sizeof(p) << std::endl; // 结果是 4 或 8,无法获取数组总大小
    cpp
  • sizeof用在函数调用上时,实际上不会调用函数,只会求得函数的返回类型所占用的字节数,例如:
    int foo() 
    {
        std::cout << "foo() 被调用" << std::endl;
        return 42;
    }
    
    int main() {
        std::cout << sizeof(foo()) << std::endl;//输出结果为4
        return 0;
    }
    cpp
    这是因为sizeof的运算是在编译器完成的,不会产生任何的运行时行为。注意sizeof不能对void函数使用,因为返回值void是没有大小的,编译会报错。
  • sizeof不能用来获取结构体中单个位域成员的大小,sizeof只能针对类型或者整个结构体,不能直接用于单个位域成员,例如:
    struct Test 
    {
        unsigned int a : 3;  // 3 bits
        unsigned int b : 5;  // 5 bits
    };
    
    int main() 
    {
        Test t;
        std::cout << sizeof(t.a) << std::endl; // 输出 4(因为 a 是 unsigned int 类型)
        std::cout << sizeof(t) << std::endl;   // 输出结构体的总大小,通常会考虑对齐
        return 0;
    }
    cpp
  • sizeof不能对不完整类型的数组求长度,会导致编译错误,例如:
    int arr[];  // 只声明,不定义(大小未知)
    int main() {
        std::cout << sizeof(arr) << std::endl;  // 编译错误,类型不完整
    }
    cpp
  • 对字面量使用sizeof会包含\0,例如:
    std::cout << sizeof("hello") << std::endl; // 输出 6,包括 '\0'
    cpp

4. sizeof的其他常见问题#

sizeof是有可能是在运行时计算的,这只发生在一种非常特殊的情况下,即对变长数组使用sizeof时。在标准的C++中,sizeof的结果始终都是一个编译时常量,编译器在编译代码时就已经确定了所有类型的大小,并将sizeof的结果替换成为一个具体数值。

变成数组是C99语言的一个特性,它允许使用一个变量来指定数组的长度:

// 这是 C 语言代码,不是标准 C++
void foo(int n) {
    int array[n]; // n 的值在运行时才知道,所以 array 是一个变长数组
}
cpp

但是我们会发现,我们在C++这样写不会报错,因为一些主流的C++编译器(特别是GCC和Clang)为了向后兼容C语言,把VLA作为一种非标准的语言扩展也引入到了C++中。所以在这种情况下,对变长数组使用sizeof是运行时进行计算的。

参考资料#

C/C++中 sizeof 详解 - 一杯清酒邀明月 - 博客园

C++ 的 sizeof 运算符
https://liangbm3.site/blog/c-de-sizeof-yun-suan-fu
Author liangbm3
Published at 2025年6月29日
Comment seems to stuck. Try to refresh?✨