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

C语言long存大数失败?unsigned long循环中异常归零问题

问题描述

我没法把4294967296及更大的数值存入long类型变量。循环第二次迭代时,尽管change是unsigned long类型,相乘后却变成0。我试过换成long long、long int等类型,也显式把所有算术操作转成unsigned long,但都没用。这个函数本来应该按字节交错两个整数(比如c245a1和1e67ba交错成c21e4567a1ba),但long和long long都存不下这么大的数。

原代码

unsigned long interleave(unsigned int i1, unsigned int i2) {
    long int out = 0l;
    unsigned long r1;
    unsigned long r2;
    unsigned long change;
    change = 1l;
    unsigned long store;
    unsigned long bitSize = 256l;
    printf("%010x + %010x = ", i1, i2);
    //printf("START CHANGE %016x or %lu\n", change, change);
    for (int i = 3; i >= 0; i--) {
        //Get remainder for int 1;
        r1 = (unsigned long)i1 % (unsigned long)bitSize;
        i1 = (unsigned long)i1 / (unsigned long)bitSize;
        //Get remainder for int 2;
        r2 = (unsigned long)i2 % (unsigned long)bitSize;
        i2 = (unsigned long)i2 / (unsigned long)bitSize;
        //printf("GOT %04x and %04x\n", r1, r2);
        store = ((unsigned long)r1 * (unsigned long)bitSize) + (unsigned long)r2;
        store = (unsigned long)store * (unsigned long)change;
        //printf("STORE %016x\n", store);
        change = ((unsigned long)change) * ((unsigned long)bitSize);
        printf("CHANGE AFTER FIRST MULTIPLICATION: %016x or %lu\n", change, change);
        change = ((unsigned long)change) * ((unsigned long)bitSize);
        printf("CHANGE AFTER SECOND MULTIPLICATION: %016x or %lu\n", change, change);
        //printf("OUT: %016x\n", out);
        out += (unsigned long)store;
    }
    printf("%016x", out);

}

int main() {
    interleave((unsigned)4294967295, (unsigned)2999999);
    char* ch;
    scanf("%c%c", ch, ch);
}
问题分析与修复方案

核心问题

  1. 类型位宽不足:目标是生成8字节(64位)的交错结果,但out被定义为long int,多数系统中long int是32位,根本存不下64位数值;就算用long long,若中间变量类型不匹配,依然会触发溢出。
  2. 无符号整数溢出回绕:change每次循环要乘以256*256=65536,在32位unsigned long环境下,第二次迭代时change会达到2^32,超过32位无符号整数最大值(2^32-1),触发溢出回绕,结果直接变为0。
  3. main函数内存错误:char* ch未初始化就传给scanf,会导致非法内存访问。

修复步骤

  1. 统一使用64位无符号类型:用uint64_t(需包含<stdint.h>)或unsigned long long存储结果和中间变量,确保有足够位宽容纳8字节数据。
  2. 修正变量定义:把out、change、store等全部改为64位无符号类型,避免类型转换导致的溢出。
  3. 调整打印格式符:打印64位无符号整数时,用%llx(对应unsigned long long)或%lx(若unsigned long是64位),避免格式不匹配。
  4. 修复main函数输入逻辑:替换未初始化的指针,用getchar()等待输入。

修复后代码

#include <stdio.h>
#include <stdint.h>

uint64_t interleave(unsigned int i1, unsigned int i2) {
    uint64_t out = 0;
    uint64_t r1, r2, change = 1;
    uint64_t store;
    const uint64_t bitSize = 256;
    
    printf("%08x + %08x = ", i1, i2);
    
    for (int i = 3; i >= 0; i--) {
        r1 = (uint64_t)i1 % bitSize;
        i1 /= bitSize;
        r2 = (uint64_t)i2 % bitSize;
        i2 /= bitSize;
        
        store = (r1 * bitSize + r2) * change;
        change *= bitSize * bitSize;
        out += store;
    }
    
    printf("%016llx\n", out);
    return out;
}

int main() {
    interleave((unsigned int)4294967295, (unsigned int)2999999);
    getchar();
    return 0;
}

额外说明

  • 无符号整数溢出是C标准定义的合法行为(自动回绕),但这不是我们需要的逻辑,必须用足够位宽的类型避免溢出。
  • uint64_t比unsigned long long更具可移植性,它明确表示64位无符号整数,在所有标准编译器环境下都能保证位宽。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:36:14