几乎每个C语言开发者天天都在用sizeof,但90%的人对它的认知都是错的——它不是函数,不参与运行时计算,甚至你写的很多括号都是多余的。本文用3个反常识真相,彻底讲透sizeof的底层规则,避开所有高频坑。
真相1:sizeof是纯编译期运算符,不是运行时函数
除了C99变长数组(VLA),所有sizeof的计算都在编译阶段完成,直接替换为常量值,不会生成任何运行时代码。
最经典的踩坑示例:
#include <stdio.h>
int main() {
int a = 10;
printf("sizeof结果:%zu\n", sizeof(a++));
printf("a的值:%d\n", a); // 输出10,a++根本没执行
return 0;
}
底层逻辑:编译期就确定了sizeof(a)是4,直接替换为常量,a++的副作用表达式被完全丢弃,不会进入运行时代码。
真相2:括号不是「函数调用符」,只是优先级控制
sizeof是单目运算符,和++、--同级,根本不是函数。跟类型名必须加括号,跟变量名完全可以不加。
int a;
sizeof a; // 完全合法,等价于sizeof(a)
// sizeof int; // 编译报错,类型名必须加括号,正确写法是sizeof(int)
高频优先级陷阱:
int *p;
// 你以为是sizeof(*p + 1),实际是(sizeof(p)) + 1
printf("%zu\n", sizeof p + 1); // 64位系统输出9,而非预期的4
底层逻辑:sizeof优先级高于加法,先算sizeof p(8字节),再加1,结果完全偏离预期。
真相3:数组名的sizeof,仅在定义的作用域内有效
数组名在函数传参时会强制退化为指针,函数内用sizeof永远只能拿到指针的大小,绝对拿不到数组总长度。
#include <stdio.h>
// 形参arr实际是int*,不是完整数组
void get_len(int arr[]) {
printf("函数内sizeof:%zu\n", sizeof(arr)); // 64位系统固定输出8
}
int main() {
int arr[5] = {
1,2,3,4,5};
printf("main内sizeof:%zu\n", sizeof(arr)); // 输出20(完整数组总大小)
get_len(arr);
return 0;
}
终极避坑总结
记住这3条,就能避开99%的sizeof相关坑:
- 非VLA场景,sizeof在编译期完成,不会执行表达式内的自增、函数调用等副作用;
- 它是运算符不是函数,注意优先级,复杂表达式必须加括号明确计算顺序;
- 函数内永远别用sizeof拿数组长度,必须手动传递数组长度参数。