Day 18: sizeof操作符的应用与陷阱

在上一讲,我们详细分析了宏定义中的优先级与副作用陷阱。今天进入 Day 18,聚焦于 sizeof操作符的应用与陷阱。这是C语言开发中极易被忽视但又影响极大的基础点,涉及类型安全、内存分配、数组与指针的本质区别等核心话题。


1. 原理与细节逐步讲解

1.1 sizeof的基本原理

  • sizeof 是一个编译时运算符,用于返回对象或类型所占的字节数(以size_t类型返回)。
  • 它可以作用于类型(如sizeof(int))、变量(如sizeof x)、表达式(如sizeof(x+1))。
  • 注意:sizeof 并不对表达式求值,只关心其类型和大小。

1.2 应用场景

  • 结构体、数组、指针大小确定。
  • 为动态分配内存(如malloc)时计算字节数。
  • 类型安全的内存拷贝(如memcpy)。

1.3 与数组、指针的关系

  • 数组名在大多数表达式中会退化为指针,但在sizeof&_Alignof等运算符下不会退化。
  • sizeof(array) 返回整个数组的大小(元素数 × 单元素大小)。
  • sizeof(pointer) 返回指针本身的大小(通常是4字节或8字节,视平台定)。

2. 典型陷阱/缺陷说明及成因剖析

2.1 指针与数组混用

int arr[10];
int *p = arr;
printf("%zu %zu\n", sizeof(arr), sizeof(p));

sizeof(arr) == 40(假设int为4字节),sizeof(p) == 8(64位平台),
误用可导致内存分配、拷贝等逻辑大错特错。

2.2 作为函数参数时的退化

void foo(int arr[10]) {
    printf("%zu\n", sizeof(arr));
}

输出的是指针大小而非数组大小,因为函数参数int arr[10]实际等价于int *arr

2.3 结构体对齐与填充

struct S { char c; int i; };
printf("%zu\n", sizeof(struct S));

实际大小通常大于成员之和,因为编译器会对齐填充。

2.4 sizeof对表达式不求值

int x = 1;
printf("%zu\n", sizeof(x++)); // x不会自增

3. 规避方法与最佳设计实践

  • 动态分配内存时,用变量而非类型作为sizeof参数,如malloc(n * sizeof(*ptr))
  • 不要在函数参数中用sizeof(arr)判断数组长度,应显式传递数组长度
  • 结构体拷贝、内存操作等用sizeof(变量)而非sizeof(类型),防止类型变更时遗漏。
  • 明确区分数组与指针,避免混用导致sizeof结果错误。

4. 典型错误代码与优化后正确代码对比

错误代码

void foo(int arr[10]) {
    size_t n = sizeof(arr) / sizeof(arr[0]); // 错误!arr是指针
    for (size_t i = 0; i < n; ++i) {
        arr[i] = 0;
    }
}

正确代码

void foo(int arr[], size_t n) {
    for (size_t i = 0; i < n; ++i) {
        arr[i] = 0;
    }
}

// 调用时
int data[10];
foo(data, sizeof(data)/sizeof(data[0]));
机制分析
  • 错误代码中,sizeof(arr)其实是指针大小,导致n==1或2,循环次数错误。
  • 正确代码将数组长度作为参数传递,保证了逻辑正确性。

5. 底层原理补充

  • sizeof编译期求值,不会真的执行表达式。
  • 数组参数退化为指针,是C语言参数传递机制决定的。
  • 指针和数组的本质区别决定了sizeof的不同表现。
  • 结构体的sizeof取决于“内存对齐填充”规则(详见Day 4)。

6. SVG图示:数组与指针的sizeof对比

在这里插入图片描述


7. 总结与实际建议

  • sizeof是C语言类型和内存操作的基石,但指针与数组、结构体对齐、表达式不求值等陷阱极多
  • 编写涉及内存分配、数组操作、结构体拷贝等代码时,一定要明确sizeof操作的对象和实际含义
  • 最佳实践:用变量而非类型做sizeof参数,数组传参时要显式传递长度,避免“指针退化”带来的悲剧。

牢记:搞清楚sizeof的对象、时机和本质,是C语言安全与可移植代码的基础!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值