← 返回学习笔记

Lecture 6:知识 - 整数的表示与运算

408 学习笔记:Lecture 6:知识 - 整数的表示与运算。保留原有知识内容、公式与图示;有对应原件时提供查看和下载入口。

本页目录

描述:整数题的核心是“同一位模式、不同解释”。有符号整数通常按补码解释,无符号整数把全部位当数值位;类型转换往往不改低位位串,只改变保留、扩展或解释方式。

2.1 无符号与有符号整数

类型 编码 $n$ 位范围 常见用途
无符号整数 全部位均为数值位,默认非负 $0\sim2^n-1$ 地址值、位掩码、对象大小及只产生非负值的计数
有符号整数 最高位参与符号,实际采用补码 $-2^{n-1}\sim2^{n-1}-1$ 普通整数运算
  • 8 位无符号数范围是 $0\sim255$;8 位有符号补码整数范围是 $-128\sim127$。无符号数省掉符号位,因此同字长最大值更大。
  • 无符号运算以模 $2^n$ 循环,例如最大无符号数加 1 回绕为 0。是否把这种回绕视为错误,取决于程序语义与语言规则。
  • 计算机有符号整数采用补码:零唯一、符号位可与数值位一起参加加减、比原码/反码多表示一个最小负数。

2.2 C 语言整型及位模式

类型(常见实现) 典型宽度 默认符号 说明
char 8 bit / 1 B 平台相关,题设若指定按其执行 用于字符或最小整数单位
short / short int 16 bit / 2 B signed 短整型
int 32 bit / 4 B signed 常用整型
long / long int 32 或 64 bit signed 依 ABI 与平台变化
unsigned short/int/long 对应类型宽度 unsigned 全部位解释为数值位
  • short、int、long 未注明 signed/unsigned 时通常是有符号整数;具体宽度不能脱离题目或平台断言。
  • 有符号与无符号整型都以相同的二进制位模式参与存储和运算;差别在于解释规则、扩展方式和比较/溢出语义。

题型:#有符号无符号转换

在本讲默认的同字长、二进制补码机器模型中,有符号数转对应无符号类型通常表现为“位模式不变,只改变解释方式”。例如:

short x = -4321;
unsigned short y = (unsigned short)x;  // y = 61215

x 的 16 位补码不变,作为无符号数解释即为 $2^{16}-4321=61215$。

  • 从 C 语言的值语义看,有符号转无符号按模 $2^n$ 得到同余值;在补码机器上通常对应相同位串。反向把超出有符号范围的无符号值转成有符号类型时,结果依语言版本和实现规则处理,不能无条件概括为“只改解释”。
  • 有符号与无符号数混合参与同一运算时,必须按 C 的具体整数提升与通常算术转换规则分析;当同等转换等级下无符号类型主导时,结果会按无符号语义解释。做 408 题需以题目给定的类型宽度和转换规则为准。
  • 不要先把负数“改成正数”再算;应先确定参与运算时每个操作数提升/转换后的位宽和类型。

2.3 不同字长的转换

2.3.1 截断与扩展

方向 操作 结果
大字长 -> 小字长 固定位宽硬件/408 题中通常截掉多余高位,只保留低位 值可能改变;对目标无符号类型可按模 $2^k$ 理解
无符号小字长 -> 大字长 零扩展 高位补 0,数值保持不变
有符号小字长 -> 大字长 符号扩展 高位复制原符号位,补码真值保持不变
  • 小字长向大字长的目标是尽量保持原数值:正数补 0,补码负数补 1。对无符号数,原最高位是数值位,故必须零扩展。
  • C 语言中,超出目标范围的有符号窄化转换不应无条件写成“保留低位”:其结果可能由实现定义;无符号目标则按模 $2^k$ 规则确定。408 若明确采用固定补码截断模型,再按题设保留低位。
  • 例如题设规定 char 为 8 位无符号数时,char -> int 应在高位补 0;若题设规定 char 是 signed,则应按符号扩展。
  • 在题设明确采用固定补码位串重解释的机器模型中,同宽有符号/无符号转换可只改变位串的解释;若位宽扩大,先按源类型规则完成零扩展或符号扩展,再按目标类型解释。C 语言的有符号转无符号按模 $2^n$ 确定;反向转换若数值超出目标有符号范围,不能不加前提地视为必然重解释。

2.3.2 与浮点类型的联系

  • 常见实现中 int 和 float 均占 4 B,double 占 8 B,但相同字节数不代表精度或编码相同。
  • 整数转浮点在有效尾数位不足时会舍入;浮点转整数截掉小数部分,且若目标范围不够会发生无法表示的情况。具体分析见浮点数一讲。

题型:#位宽与转换跟踪

第一部分:固定步骤

  • 写出源值在源字长下的完整二进制位串;负数必须先写补码。
  • 判断是同宽重解释、缩窄截断,还是拓宽扩展。不要因目标类型为无符号就错误地给源负数“取绝对值”。
  • 拓宽时先看源类型:无符号零扩展,有符号补码符号扩展;缩窄时,只有题设采用固定补码截断模型或目标为无符号类型,才可直接按保留低位计算。目标为有符号类型且结果超出范围时,还需按语言或题设规则判断。
  • 最后按目标类型解释保留下来的位串,并检查后续表达式是否还会触发整数提升或有/无符号混合转换。

第二部分:典型例子

操作(假设) 位级过程 结果
uint8_t 255 -> int32_t 11111111 零扩展为 000...0011111111 $255$
int8_t -1 -> int32_t 11111111 符号扩展为全 1 $-1$
int16_t -4321 -> uint16_t 16 位模式不变,改变解释 $65536-4321=61215$
int32_t 0x12345678 -> uint16_t 截断高 16 位,仅保留 0x5678 $22136$
  • 当运算的实际类型确为 $n$ 位无符号类型时,其结果按模 $2^n$ 定义;例如无符号 $0-1$ 得到 $2^n-1$。但 uint8_t、uint16_t 等窄类型在 C 表达式中常先提升为 int,要在赋值或强制转换回窄类型时才发生相应截断。
  • 对有符号数,数学结果超出范围属于有符号溢出语义,不能因为硬件同样产生回绕位串就把它直接当作语言层面合法结果。
  • 底层地址值、对象大小和位掩码常用无符号整数表示;C 指针本身是独立的指针类型,不应简单等同于无符号整数。指针差值使用 ptrdiff_t,边界与长度常涉及 size_t,需按具体类型分析。
  • 题中出现十六进制常量时,先按位写出再转换最稳妥:每个十六进制数码对应 4 位,避免在十进制与二进制之间反复心算导致漏位。

相关知识

2.4 本节复盘

  • $n$ 位无符号数范围为 $[0,2^n-1]$,有符号补码整数范围为 $[-2^{n-1},2^{n-1}-1]$。
  • 同一位串可表示不同数值;转换题先定目标类型和位宽,再判断是重解释、截断、零扩展还是符号扩展。
  • 固定补码截断模型下,大转小保留低位;小转大时,无符号零扩展、有符号补码符号扩展。C 语言有符号窄化越界另依转换规则判断;char 的符号性必须看题设/平台。
  • C 的混合有/无符号运算需先按类型提升与转换规则处理,不能只凭数学直觉判断。