1. 从sizeof看数组与指针的本质差异
在嵌入式开发中,我经常遇到新手工程师将数组和指针混为一谈的情况。让我们从一个简单的实验开始:
c复制char arr[10];
char *p = arr;
printf("sizeof(arr)=%zu, sizeof(p)=%zu\n", sizeof(arr), sizeof(p));
在32位系统上运行,你会看到输出:
code复制sizeof(arr)=10, sizeof(p)=4
这个结果揭示了数组和指针的第一个关键区别:
- 数组名代表的是整个内存块的大小(这里是10字节)
- 指针变量只存储地址,其大小固定(32位系统4字节,64位系统8字节)
重要提示:在函数参数传递时,数组会退化为指针,此时sizeof将返回指针大小而非数组大小。这是许多bug的根源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 内存访问机制的底层解析
2.1 数组的直接访问模式
当编译器看到arr[3]这样的表达式时:
- 它知道arr的基地址(比如0x1000)
- 直接计算0x1000 + 3*sizeof(char) = 0x1003
- 从该地址读取数据
这种访问没有运行时开销,就像直接走进一栋已知门牌号的房子。
2.2 指针的间接访问模式
对于p[3]的访问:
- CPU必须先读取指针变量p的值(假设存储在0x2000)
- 从0x2000处获取地址值(比如0x1000)
- 再计算0x1000 + 3*sizeof(char) = 0x1003
- 最后访问0x1003处的数据
这种间接访问在嵌入式实时系统中可能带来不可预测的延迟。
3. 多文件编程中的致命陷阱
考虑以下场景:
sensor.c:
c复制char sensor_data[100];
process.c:
c复制extern char *sensor_data; // 错误的声明
void process() {
char value = sensor_data[0]; // 灾难发生点
}
这个看似合理的代码会导致:
- 链接器仅检查符号名称,不检查类型
- process.c将sensor_data当作指针处理
- CPU
