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

C语言中32位无符号整数内存直接相加存64位内存溢出问题

问题分析:32位无符号整数相加结果存入64位内存区域的溢出问题

需求背景

有三个uint8_t*类型指针n1->bits、n2->bits、R->bits指向数百字节的内存区域,需完成以下操作:

  • 从n1和n2中取出第i对32位数据,视为uint32_t无符号整数
  • 将两个数相加(含uint32_t类型的carry),结果存入R中对应位置的连续64位空间(容纳32位相加可能产生的33位结果)
  • 要求直接通过内存操作完成,不借助临时uint32_t变量

现有实现代码

*((uint64_t*)( ((uint32_t*)(R->bits)) + i)) = 
            *( ((uint32_t*)(n1->bits)) + i)
            +
            *( ((uint32_t*)(n2->bits)) + i)
            +
            carry;

对代码逻辑的理解(用户视角)

    1. 通过R->bits获取结果内存区域的首地址
    1. 将指针强制转换为uint32_t*,确保指针算术+i时以32位(4字节)为单位递增,定位到第i个32位整数的起始位置;若不转换,uint8_t*的+i仅会偏移i个字节,无法正确定位目标
    1. 转换为uint32_t*后执行+i,得到第i个32位整数的起始地址
  • 4a. 对两个操作数,通过强制转换和指针算术得到的指针解引用,直接读取对应位置的32位无符号整数
  • 4b. 对结果缓冲区,将指向第i个32位区域的指针强制转换为uint64_t*,再解引用赋值,期望编译器将加法结果存入该起始地址后的连续64位空间,容纳32位相加产生的进位

实际问题现象

测试时将两个操作数内存区域填充为数百个0x01字节,第一个32位数据相加后预期得到64位结果:0x00000001FFFFFFFE(二进制为00000001 11111111 11111111 11111111 11111110)。

由于机器是小端序,预期内存布局为:0xFE 0xFF 0xFF 0xFF 0x01(后续字节为0)。但实际查看结果缓冲区时,第5个字节(对应64位结果的高位)全为0,加法结果发生溢出,高位进位丢失。

问题原因解析

1. 加法运算结果被截断为32位

代码中,*(uint32_t*)...和carry都是uint32_t类型,根据C语言的整数运算规则,多个uint32_t相加的结果类型仍然是uint32_t。这意味着即使相加结果超过32位,超出的高位会被无符号溢出自动截断,仅保留低32位值。之后将这个截断后的值赋值给uint64_t*指向的空间时,编译器会自动将uint32_t零扩展为uint64_t,高位字节自然全部为0,这就是你看到第5个字节为0的核心原因。

2. 指针转换的逻辑误区

你错误地认为将uint32_t*强制转为uint64_t*就能让加法结果以64位形式存入,但问题的根源不在赋值的目标类型,而在加法运算本身的结果类型。无论目标是uint64_t还是其他类型,只要右边的表达式结果是uint32_t,就只能得到被截断后的值,无法保留进位。

正确实现思路

要解决这个问题,需要在加法运算前将操作数提升为uint64_t类型,确保运算结果是64位,完整保留进位:

*(((uint64_t*)R->bits) + i) = 
    (uint64_t)*((uint32_t*)n1->bits + i) 
    + (uint64_t)*((uint32_t*)n2->bits + i) 
    + carry;

这里先把每个32位操作数强制转换为uint64_t,加法运算的结果自然是uint64_t类型,能完整保留32位相加产生的进位,再赋值给uint64_t*指向的空间,即可得到正确的64位结果。

注:需确保R->bits的地址满足uint64_t的对齐要求,否则强制转换为uint64_t*可能触发未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:17:11