将静态数组声明为指针为何引发Cortex-A9的数据中止错误?
问题分析:Cortex-A9上数组与指针extern声明不匹配导致数据中止错误
问题场景
在ZYNQ 7000(Cortex-A9)平台上,将网络接收的数据存入RAM静态数组时出现异常:
- 当
network.c中用extern char *dataBuffer;声明外部数组时,拷贝过程触发数据中止错误,且错误固定在recvLen=196172时发生 - 改用
extern char dataBuffer[16777216];声明则运行正常
使用编译器为arm-none-eabi-gcc。
相关代码
data.c
char dataBuffer[16777216];
network.c
#include <string.h> extern char *dataBuffer; // 触发数据中止错误 // extern char dataBuffer[16777216]; // 正常运行 int recvLen = 0; int IsLengthValid(int recvLen, int len); void OnReceivingData(const char *data, int len){ if(IsLengthValid(recvLen,len)){ memcpy(&dataBuffer[recvLen],data,len); recvLen += len; } }
根本原因:数组与指针的本质类型不匹配
C语言中数组名和指针看似相似,但本质完全不同:
- 在
data.c中,dataBuffer是静态字符数组,它本身是数组首元素的常量地址,编译器为它分配了16MB的连续RAM空间,数组名直接代表这个空间的起始地址(不是一个占用内存的指针变量)。 - 错误声明为
extern char *dataBuffer;时,编译器会把dataBuffer当成一个32位指针变量(Cortex-A9是32位架构,指针占4字节内存),而非数组的起始地址。
错误的内存访问逻辑
当执行&dataBuffer[recvLen]时,实际操作完全偏离预期:
- 编译器会尝试读取
dataBuffer这个“指针变量”的值,但这里根本不存在指针变量——它把数组的起始地址区域当成了指针变量的存储位置,读取到的是数组前4字节的内容(假设数组初始为0,读取到的“指针值”就是0x00000000)。 - 加上
recvLen的偏移量后,访问地址变为0x0003001C(196172的十六进制值),这个地址大概率属于未映射RAM、外设空间或无访问权限的区域,直接触发硬件层面的数据中止异常。
为什么错误固定在recvLen=196172时触发?
当recvLen累计到196172时,计算出的访问地址0x0003001C刚好落在了你的系统中未配置访问权限的地址范围,此时第一次触发硬件异常,程序直接终止,所以错误总是停在这个数值上。
正确解决方式
必须保证extern声明与变量定义的类型完全一致:
- 数组定义对应数组声明:可以写
extern char dataBuffer[];(省略长度也有效),或带完整长度的声明 - 指针定义才对应指针声明
内容的提问来源于stack exchange,提问作者Jackoo
相关产品推荐
相关产品推荐

