在C语言中,sizeof 是一个操作符(operator),而不是函数。它的作用是计算数据类型或者表达式所占用的内存字节数。通常有两种使用形式:
(1)sizeof(类型说明符)
(2)sizeof 表达式
我们一般更常用第一种带括号的形式。
它的返回值类型是 size_t,这个类型在头文件 stddef.h 中定义。其本质是一个依赖于编译系统的无符号整数,通常在32位环境下类似这样定义:
typedef unsigned int size_t;
在深入学习之前,我们先确定一下当前编译环境中,C语言基本数据类型的字节大小。以下是一个简单的测试程序,请注意,本文示例的运行环境均为32位。
#include <stdio.h>
int main(void)
{
printf("sizeof(char) = %u\n", sizeof(char));
printf("sizeof(short) = %u\n", sizeof(short));
printf("sizeof(int) = %u\n", sizeof(int));
printf("sizeof(long) = %u\n", sizeof(long));
printf("sizeof(float) = %u\n", sizeof(float));
printf("sizeof(double)= %u\n", sizeof(double));
return 0;
}
程序运行的输出结果如下:

从结果可以看到,在典型的32位环境中,char 占1字节,short 占2字节,int、long、float 均占4字节,double 占8字节。这些基础知识是理解后续内容的前提。
一个看似简单却极易出错的例子
sizeof 的基础概念听起来很简单,对吧?那么,下面这段代码的输出结果,你能准确预测出几个呢?😏
#include <stdio.h>
int main(void)
{
char *s = "hello";
printf("sizeof(char) = %u\n", sizeof(char));
printf("sizeof(char*)= %u\n", sizeof(char*));
printf("sizeof('a') = %u\n", sizeof('a'));
printf("sizeof(*s+0) = %u\n", sizeof(*s+0));
printf("sizeof(*s) = %u\n", sizeof(*s));
printf("sizeof(s) = %u\n", sizeof(s));
return 0;
}
实际的运行结果是:

怎么样,有没有被其中几个结果“惊喜”到?没懵的话算我输 😑。

结果逐条分析
别急,我们来逐一拆解这些结果背后的原理。理解这些细节,对于掌握 C 语言的底层内存管理和编译行为至关重要。
-
sizeof(char) = 1
这个最直接,C 语言标准规定 char 类型的大小为 1 字节。
-
*`sizeof(char) = 4** 这里计算的是指针本身的大小。在 32 位环境中,无论是什么类型的指针(char、int等),其大小通常都是 4 字节,因为它存储的是一个 32 位的地址。这与unsigned int` 的字节长度是一致的。
-
sizeof(‘a’) = 4
这是第一个容易让人困惑的点。为什么一个字符常量占了 4 字节?
在 C 语言中,字符常量(如 ’a’)的类型实际上是 int,而不是 char。因此 sizeof(‘a’) 计算的是 int 类型的大小,在 32 位环境下自然是 4 字节。你可以把它理解为字符 ’a’ 对应的 ASCII 码值(十进制 97)作为一个整数存储。
需要注意的陷阱:如果你这样定义 char ch = ‘a’;,那么 sizeof(ch) 的值就是 1,因为 ch 是一个明确声明为 char 类型的变量。所以,上下文环境决定了 sizeof 的计算对象。
-
sizeof(*s+0) = 4*
表达式 `s取到的是字符串”hello”的第一个字符’h’。然后’h’ + 0` 进行了算术运算。这里涉及到了 C 语言的隐式类型转换*(或称“整型提升”)。当 char 类型参与算术运算时,它会首先被转换为 int 类型。因此,整个表达式 `s+0的结果类型是int,sizeof` 计算其大小得到 4。
C 语言中类型转换的规则可以总结为下图(图片来源网络),它清晰地展示了不同数据类型混合运算时的转换方向:

图注:注意,float 类型与除 double 外的类型运算后,结果仍为 float。
-
*`sizeof(s) = 1** 这与第 3 点形成对比。这里的s是一个char类型的值(字符’h’)。sizeof计算的是这个char类型值本身的大小,所以是 1。关键点在于,这里的s` 没有参与任何会引发类型转换的运算。
-
sizeof(s) = 4
这里的 s 就是我们定义的变量,它是一个 char* 类型的指针。因此,和第二条一样,计算的是指针变量本身的大小,在 32 位环境下为 4 字节。
总结与思考
通过这个精心设计的例子,我们可以更深刻地理解 sizeof 操作符:
sizeof 是操作符,不是函数,它在编译时就完成计算。
- 计算字符常量(如
’a’)时,其类型是 int。
- 当
char、short 等小于 int 的类型参与表达式运算时,会发生整型提升,这会直接影响 sizeof 的结果。
- 计算指针时,
sizeof 得到的是指针变量本身存储地址所需的内存大小,与它指向的数据类型和内容无关。
- 同样一个字符,在不同的上下文(是独立常量,还是变量值,亦或是表达式的一部分)中,
sizeof 的结果可能天差地别。
掌握这些细微之处,不仅能帮助你在笔试面试中应对此类刁钻问题,更能让你在编写涉及底层内存操作、数据对齐或平台移植的代码时,做到心中有数,避免潜在的 Bug。希望这篇解析能帮你把 sizeof 弄得明明白白。如果在实践中遇到其他有趣的问题,欢迎到云栈社区与更多开发者一起交流探讨。