欢迎光临
我们一直在努力

整数在计算机里:为什么存的是补码,输出的却是原码?

我们都知道计算机用补码存整数,但printf出来的却是原码。这中间发生了什么?本文带你走一遍从代码到内存再到输出的完整流程。

一、先记住这一句

整数在内存中永远存补码,但输出时会根据格式控制符转成原码显示。

为什么?

  • 存补码:计算机只用加法器就能处理减法

  • 输出原码:人类只看懂带符号位的原始形式

二、完整流程

阶段步骤
存入内存 原始数值 → 写出原码 → 按变量类型调整位数 → 转补码 → 存入内存
输出屏幕 读取补码 → 按格式符调整位数 → 转原码 → 转十进制 → 显示

看不懂没关系,后面每步都会拆开细讲,看完再回来看这张表就懂了。

三、整数存入计算机(原码 → 补码)

当你定义一个变量并赋值时(如 char a = -5 或 long long b = 100),计算机按以下两步处理:

① 写出原码

直接按定义的类型写出原码。

定义原码
char a = -5 10000101(8位)
short b = -5 10000000 00000101(16位)
int c = -5 10000000 00000000 00000000 00000101(32位)
long long d = -5 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101(64位)

规则:最高位是符号位(0正1负),后面跟数值绝对值的二进制。

② 转成补码(最终存储)

规则:

  • 正数/无符号数:补码 = 原码(不变)

  • 有符号负数:补码 = 原码的符号位不变,数值位取反,再加1

示例:

步骤char a = -5(8位)int b = -5(32位)
①原码 10000101 10000000 00000000 00000000 00000101
②取反 11111010 11111111 11111111 11111111 11111010
③加1 11111011 11111111 11111111 11111111 11111011
内存 11111011 11111111 11111111 11111111 11111011

四、计算机输出整数(补码 → 原码)

当你用printf输出时(如 printf("%d", a)),计算机反向操作:

① 读取补码

从内存中取出之前存的补码:11111011(以char a = -5为例)

② 按格式控制符调整位数

看你是用%d、%u、%hd还是%hhd,按目标类型调整位数:

情况A:格式符位数 > 变量位数 → 符号扩展

  • 有符号数:高位补符号位(正数补0,负数补1)

  • 无符号数:高位补0

情况B:格式符位数 < 变量位数 → 截取低位

情况C:格式符位数 = 变量位数 → 不变

示例:char a = -5 用 %d 输出

阶段位数二进制
char补码 8位 11111011
符号扩展(负数补1) 32位 11111111 11111111 11111111 11111011

③ 还原成原码

类型还原规则
正数/无符号数 补码直接就是原码,无需转换
有符号负数 补码 → 减1 → 数值位取反(符号位不变)

示例:%d输出-5

步骤二进制
补码(规整后) 11111111 11111111 11111111 11111011
减1 11111111 11111111 11111111 11111010
取反(符号位不变) 10000000 00000000 00000000 00000101
原码结果 = -5

④ 转十进制输出

原码 10000000 00000000 00000000 00000101 = -5,屏幕上显示 -5

五、示例:同一份内存,不同的输出结果

示例1:%d vs %u

char a = -5; // 内存中存的是补码:11111011
printf("%d\\n", a); // 输出:-5
printf("%u\\n", a); // 输出:4294967291

  • 用%d输出:11111011 → 符号扩展成32位11111111 11111111 11111111 11111011 → 减1取反得原码10000000 00000000 00000000 00000101 = -5

  • 用%u输出:11111011 → 符号扩展成32位11111111 11111111 11111111 11111011 → 直接当无符号数解读 = 4294967291

核心:同一内存,不同格式符,输出不同。

示例2:%hu 输出

char a = -5;
printf("%hu\\n", a); // 65531

处理流程:

  • 整型提升:11111011 → 符号扩展成32位 11111111 11111111 11111111 11111011

  • 截取低16位:11111111 11111011

  • 当无符号数解读:65531

  • 示例3:-128的特殊情况

    char a = -128;
    printf("%hu\\n", a); // 65408

    -128的补码是 10000000

    处理流程:

  • 整型提升:10000000 → 符号扩展成32位 11111111 11111111 11111111 10000000

  • 截取低16位:11111111 10000000

  • 当无符号数解读:65408

  • 六、核心总结

    6.1.存储与输出的完整流程

    存储时:按定义类型写原码 → 负数取反加一转补码 → 存内存

    输出时:取补码 → 按格式符做整数提升/截断 → 负数减一取反转原码 → 显示

    6.2.三个核心概念

  • 计算机只认补码:内存里永远存的是补码

  • 人类只看原码:输出时一定要还原成原码

  • 格式控制符决定最终看到什么:同一块内存,用%d和%u看完全不同

  • 6.3.整数提升规则

    • 小类型(char、short)做运算或传参时,先转成int

    • 有符号按符号位扩展,无符号补0

    七、练习题

    分析下面代码的输出:

    char a = -1;
    printf("%d %u %hu %hhu\\n", a, a, a, a);

    答案:

    • %d:-1

    • %u:4294967295

    • %hu:65535

    • %hhu:255

    你能按流程推出来吗?

    结语

    现在你明白了吗?

    • 存补码:是为了让计算机好计算

    • 输出原码:是为了让人类能看懂

    • 中间经历了整数提升 + 符号扩展/截断 + 原反补转换

    下次再看到奇怪的输出结果,不妨按这个流程走一遍,保证能看懂!

    赞(0)
    未经允许不得转载:171主机测评 » 整数在计算机里:为什么存的是补码,输出的却是原码?
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址