You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

uint16_t数组赋值时内存地址异常变更致段错误问题求助

问题排查:uint16_t数组初始化时内存偏移导致段错误

问题场景

尝试将uint16_t数组的所有值初始化为0时,处理到索引4出现异常:该位置初始垃圾值为58248,赋值为0后内存地址发生58248的偏移,随后触发段错误。其他类似场景无此问题。

代码实现

头文件声明

typedef struct my_struct
{
    //various struct members
} my_struct;   

typedef union my_struct_union 
{
    my_struct struct_instance;
    uint16_t struct_overlay[6];
} my_struct_union;

extern my_struct_union *struct_pointer;
extern my_struct struct_instance;

源文件代码

my_struct_union *struct_pointer;
my_struct struct_instance;

void init_struct()
{
    struct_pointer = (my_struct_union *)&struct_instance;

    for(uint16_t indx = 0; indx < 6; indx++)
    {
        printf("indx: %d", indx);
        printf("address: %d", &struct_pointer->struct_overlay[indx]);
        printf("value: %d", struct_pointer->struct_overlay[indx]);

        struct_pointer->struct_overlay[indx] = 0;

        printf("address: %d", &struct_pointer->struct_overlay[indx]);
        printf("value: %d", struct_pointer->struct_overlay[indx]);
    }
        
}

异常输出

indx: 3
address: 6415246
value: 0
address: 6415246
value: 0
indx: 4
address: 6415248
value 58248
address: 6357000

随后触发段错误。

排查思路

  • 检查my_struct的实际大小与布局:共用体大小由最大成员决定,struct_overlay是6个uint16_t(共12字节,假设uint16_t为2字节)。用sizeof(my_struct)确认结构体实际大小,如果小于12字节,那么struct_overlay[4]和struct_overlay[5]属于越界访问,会篡改结构体之外的内存。同时要考虑内存对齐,比如结构体成员是否有uint32_t、指针等类型,编译器会插入填充字节,需对齐计算实际大小。

  • 验证指针转换的合法性:将my_struct*强制转为my_struct_union*需满足对齐要求。用_Alignof(my_struct)和_Alignof(my_struct_union)检查两者的对齐规则是否一致,如果共用体对齐要求更高,强制转换后访问成员会触发未定义行为。

  • 排查内存覆盖问题:

    • 确认struct_pointer本身是否被篡改:在循环中打印struct_pointer的地址,看其值是否在赋值struct_overlay[4]后发生变化。如果struct_overlay[4]的内存位置恰好覆盖了struct_pointer的存储地址,赋值0会直接修改指针的值,导致后续访问地址偏移。
    • 检查是否有其他代码意外修改struct_instance的内存区域,比如全局变量的内存重叠、栈溢出(如果是栈变量的话)。
  • 修正printf格式化错误:代码中用%d打印内存地址是错误的,应该用%p并转换为void*类型,错误的格式化符可能导致地址显示异常,干扰排查。修正后的打印语句:

    printf("address: %p", (void*)&struct_pointer->struct_overlay[indx]);
    
  • 检查编译器优化与严格别名规则:

    • 尝试关闭编译器优化(如-O0)重新编译,看问题是否消失。激进优化可能对类型双关代码产生未定义行为。
    • 确认是否违反严格别名规则:虽然共用体的方式理论上允许类型双关,但部分编译器的严格模式会对此报错,需检查编译警告信息。
  • 确认内存越界的连锁影响:如果struct_overlay[4]访问的是其他变量的内存,赋值0会修改该变量的值。如果该变量是指针或地址相关数据,会直接导致后续内存访问出错。可以打印&struct_pointer的地址,对比&struct_pointer->struct_overlay[4]的地址,看是否存在重叠。

内容的提问来源于stack exchange,提问作者mgrenier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 18:55:09