C语言中负数在计算机内部的二进制表示方式(以补码表示负数、整数的范围及所占字节数)

本文深入解析了计算机内部如何使用二进制和补码表示负数,揭示了正负数在二进制下的独特表示方式及范围,通过实例说明了不同数据类型在C语言中的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

负数在计算机内部的表达

众所周知 在计算机的内部 一切都是二进制
18转换为二进制是00010010
0转换为二进制是00000000

那么 负数该如何表达?

在十进制中 负数用-来表示
在十进制的带有负号的运算中 会先进行数字的运算 然后将负号单独处理
但二进制可以表达的数只有0-255 这是因为只能从00000000-11111111

事实上 在计算机中 二进制使用的是补码的方式来表示负数
补码 即为二进制中的11111111(请注意 并不是作为纯二进制 而是补码 若是纯二进制那么就是255了)

由于十进制的0转换为二进制是00000000 十进制的1转换为二进制是00000001
那么 十进制的 -1+1=0 换成二进制的话 那就是11111111+00000001=100000000(多出一位去除)=00000000

二进制的11111111 作为补码 即为 -1
因此 二进制的11111111 有了【两重身份】 既是补码 又是255

补码

对于一个十进制的数 -a
那么 它的补码就是0-a

但在二进制中 实际上是2^n-a(n为a的类型的位数)
举个栗子 若为八位数 那么2^8=256 二进制最多只能表示255 那么256即为100000000
100000000-a之后得到的结果 即为补码

画个草图 以十进制的3为例:
在这里插入图片描述
将补码和原码相加之后 可以得到溢出的0

整数的范围

对于8位的二进制数 从00000000 - 11111111

其中:

  • 00000000表示十进制的0
  • 11111111 ~ 10000000表示十进制的 -1 ~ -127
  • 00000001 ~ 01111111表示十进制的 1 ~ 127

我们发现一个特征:负数的最高位(也就是最左边)为1 而正数的最高位为0

对于一个字节 比如11111111
将它以二进制的形式看待 那就是255
但是 若以整数(char)看待 那就是-1

下面以一个小例子来演示:

char c=255;
int i=255;
printf("c=%d,i=%d",c,i); // c=-1,i=255

(它们是不一样的)

这是因为 在int中 数据是32bit的 即 有4组8位bit
以上面的代码为例 变量c里就是11111111 最高位为1 因此是负数
而变量i里就是00000000 00000000 00000000 11111111 最高位为0 因此是正数

在C中 不同的整数有不同的大小:

所占字节数:

正数永远比负数少一个的原因是 在整数中不仅仅只有正数和负数 还有个0
而0的二进制是00000000 最高位也是为0(我们知道最高位为0的是正数)
但关键来了 十进制的0却并不是正数 因此它在二进制中占据了正数的一个名额(相当于是凑热闹的🤣)
正因如此 正数比负数少了一个
(高中计算机课一直不知道为什么正数比负数少一个…学了C才知道…)

  • char - 1字节 -128~127
  • short - 2字节 -32768~32767
  • int - 4字节(取决于寄存器CPU是32还是64) -(2^31) ~ (2^31)-1
  • long - 8字节(有可能是4字节 取决于寄存器CPU是32还是64)
  • long long(C99独有) - 8字节

注:1字节=8比特(bit)

所有整数范围都是-2^(n-1) ~ 2^(n-1)-1(n为bit数)


<think>我们正在讨论C语言中int类型在64位系统下的二进制表示范围。注意,在C语言中,int类型通常是32位的,无论是在32位还是64位系统(由编译器决定,但通常保持32位)。但为了回答用户的问题,我们需要确认标准。 关键点: 1. C标准规定int至少为16位,但通常在现代系统中(包括64位系统),int是32位的。 2. 我们假设讨论的是32位int(这是最常见的)。 对于32位有符号整数(int): - 最高位是符号位(0表示正数,1表示负数)。 - 正数的表示范围:0到2^31-1(因为符号位为0,剩下31位表示数值,且全1时最大) - 负数表示范围:-1到-2^31(注意:负数表示采用补码形式,最小值是-2^31,而最大值是-1) 具体范围: - 最小负数:0x80000000(二进制:10000000 00000000 00000000 00000000)对应的值是 -2^31 = -2147483648 - 最大正数:0x7FFFFFFF(二进制:01111111 11111111 11111111 11111111)对应的值是 2^31-1 = 2147483647 因此,32位有符号整数表示范围是:$[-2147483648, 2147483647]$ 但是,用户问的是64位系统下,注意:64位系统下,int通常仍然是32位。不过,有些系统可能提供更大的int,但按照标准,我们通常认为int是32位。 如果考虑真正的64位整数,那么应该使用long long(64位)或int64_t(如果支持)。 不过,为了严谨,我们可以检查当前系统下int的大小(使用sizeof(int)),但用户没有指定具体环境,所以我们按照标准情况(32位)来回答。 二进制表示形式: - 正数:原码、反码、补码相同(因为正数的补码就是其本身)。 - 负数:以补码形式存储(原码取反加1)。 举例: - 最大的正数:2147483647 二进制:01111111 11111111 11111111 11111111 - 最小的负数:-2147483648 二进制:10000000 00000000 00000000 00000000 注意:这个值很特殊,因为它的补码就是它本身(没有原码和反码的对应,因为原码不能表示-2147483648,因为原码的0有两种表示,而补码统一了0的表示)。 为什么负数范围比正数多一个? - 因为0用了正数范围中的一个位置(0的表示是0000...0000),而负数则没有0,所以负数范围从-1到-2^31,共2^31个数,正数范围从0到2^31-1,也是2^31个数,但0到2^31-1实际上是2^31个数(包括0),所以正数部分最大是2^31-1(不包括0的最大正数),而负数部分最小是-2^31(没有对应的正数)。 因此,总结: - 32位int的表示范围:$[-2^{31}, 2^{31}-1]$ 即 $[-2147483648, 2147483647]$ 如果用户问的是64位系统下的long类型,那么通常是64位的,但int不是。 生成相关问题: 1. 如何用C语言程序获取当前系统下int类型的取值范围? 2. 为什么负数范围比正数多一个? 3. 64位系统下,C语言中long类型的位数是多少? 4. 如何用二进制形式输出一个整数? 注意:在回答中,我们使用LaTeX公式表示范围,如$[-2^{31}, 2^{31}-1]$。</think>在64位系统下,C语言的`int`类型通常是**32位**(4字节)的有符号整数,其二进制表示范围遵循补码规则。以下是详细分析: ### 1. **二进制表示范围** | 类型 | 最小值 (十进制) | 最大值 (十进制) | 二进制表示补码形式) | 十六进制表示 | |------------|-------------------|-------------------|-------------------------------------------|-------------| | **正数范围** | $0$ | $2^{31}-1$ | `01111111 11111111 11111111 11111111` | `0x7FFFFFFF` | | **负数范围** | $-2^{31}$ | $-1$ | `10000000 00000000 00000000 00000000` | `0x80000000` | | | | | `11111111 11111111 11111111 11111111` | `0xFFFFFFFF` | - **总范围**:$[-2147483648, 2147483647]$ (即 $[-2^{31}, 2^{31}-1]$) > ⚠️ 注意:64位系统下`int`仍是32位(由C标准规定),与指针长度(64位)无关[^1][^2]。 --- ### 2. **关键原理** 1. **补码规则**: - 最高位为符号位(`0`正`1`负)。 - 正数:原码 = 反码 = 补码。 - 负数补码 = 反码 + 1(反码是原码除符号位取反)[^2]。 2. **负数范围比正数多1**: - 最小负数 $-2^{31}$(`0x80000000`)无对应正数,因为 $+0$ 用了 `0000...0000`[^2]。 3. **特殊值**: - $-1$ 的补码:全`1`(`0xFFFFFFFF`)。 - $0$ 的补码:全`0`(无正负区分)[^1]。 --- ### 3. **验证程序** ```c #include <stdio.h> #include <limits.h> int main() { int min = INT_MIN; // -2147483648 int max = INT_MAX; // 2147483647 printf("最小值: %d (十六进制: 0x%x)\n", min, min); printf("最大值: %d (十六进制: 0x%x)\n", max, max); return 0; } ``` **输出**: ``` 最小值: -2147483648 (十六进制: 0x80000000) 最大值: 2147483647 (十六进制: 0x7fffffff) ``` --- ### 4. **64位系统的影响** - `int` **仍是32位**:编译器保持兼容性。 - `long` 和指针变为64位: - `long` 范围:$[-2^{63}, 2^{63}-1]$ - `int*`(指针):64位地址空间。 --- ### 相关问题 1. 如何用C语言打印整数二进制表示形式?[^3] 2. 为什么`int`在64位系统下仍是32位? 3. 补码规则如何避免整数溢出的问题? 4. `unsigned int`的表示范围是多少? [^1]: 负数补码是全`1`,如`-1=0xFFFFFFFF`。 [^2]: 负整数的原码、反码、补码转换规则。 [^3]: 递归实现十进制转二进制输出。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值