首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >揭秘整数内存密码:从原码到补码,读懂计算机 “数字语言”

揭秘整数内存密码:从原码到补码,读懂计算机 “数字语言”

作者头像
Vect_
发布2025-12-18 17:43:02
发布2025-12-18 17:43:02
2270
举报

1.1. int类型变量的声明、定义、赋值

C/C++语言中,有很多种类型,而整型是用的最多的

声明一个变量:

代码语言:javascript
复制
int num; // 声明一个整型变量

声明并初始化一个变量:

代码语言:javascript
复制
int cnt = 0; // 声明并初始化一个变量

先声明一个变量,再赋值:

代码语言:javascript
复制
	// 先声明一个变量 再赋值
	int exm; // 声明一个变量,它的值是随机的
	exm = 10;// 给这个变量赋值

上面这两行代码和int exm = 10;的作用是一样的,但是赋值和初始化是两个不同的操作,

赋值是给已经存在的变量进行操作,初始化是在变量定义时进行操作

1.2. 未初始化的变量

必须强调这里未初始化的危险。如果一个变量没有初始化,C/C++ 编译器不会报告错误,甚至不会发出警告。C/C++标准中未初始化变量的值也没有明确定义。你可能会从一个未初始化的变量中得到一个随机值。为了程序的健壮性,强烈建议初始化变量,哪怕不知道这个变量到底值为多少,初始化成0也是很好的

代码语言:javascript
复制
int main() {
	int num1;
	int num2 = 10;
	cout << num1 << endl << num2 << endl;
}

VS2022强制检查,报错了

在这里插入图片描述
在这里插入图片描述

使用C语法也一样报错

在这里插入图片描述
在这里插入图片描述

2. 其他的整型

int 的宽度(以位为单位)在 C 和 C++ 标准中并不是固定的。标准 int 应具有 32 位。除了 int,还有 short intlong intlong long int``short int 是 16 位。int 是 16 位或 32 位。long int 是 32 位或 64 位(取决于编译器)。long long int 是 64 位。char 也是一种常用的整数类型。有人可能会感到困惑,认为 char 仅用于字符。由于字符被编码为整数值,char 确实是一种整数类型,并且具有 8 位。char 对英语字符来说足够宽,但对中文和其他一些字符则不够。char16_tchar32_t 已在 C++11 中引入,表示 16 位和 32 位的范围。

代码语言:javascript
复制
char c = 'C'; // ASCII码为80
代码语言:javascript
复制
char c = 80;// 十进制80
代码语言:javascript
复制
char c = 0x50;// 十六进制50 转为十进制80

上面这三行代码是等效的,在我们编码时,看着每个变量的类型不同,其实到计算机底层,所有数据都被表示成01串了,机器只能识别01两个指令

以下是各个整型类型所占空间大小

类型

所占比特位大小

char

8

short (short int)

16

int

16 or 32

long (long int)

32 or 64

long long (long long int)

64

我们可以用sizeof操作符来获取类型大小

代码语言:javascript
复制
int main() {
	cout << sizeof(char) << endl;
	cout << sizeof(short) << endl;
	cout << sizeof(int) << endl;
	cout << sizeof(long) << endl;
	cout << sizeof(long long) << endl;

	return 0;
}
在这里插入图片描述
在这里插入图片描述

在我的机器上long是四字节

有符号和无符号数

signedunsigned 可以在整数类型名称之前使用,以指示整数是有符号的还是无符号的。当整数是有符号时,关键字 signed 可以省略。这意味着 int 是用于 signed int,而 short 是用于 signed short。如果整数是有符号的,最高位(int 的第 32 位)将是其符号位。如果符号位为 1,则为负数;如果为 0,则为正数

有符号整数和无符号整数如下面的图所示:

在这里插入图片描述
在这里插入图片描述

3. 整型数据的存储

3.1. 原码表示法

数据在底层用0和1这两个数存储,一个字节(8bit)可以表达多少个数?————>每个位置两种选择,共八个位置:

2^8

在这里插入图片描述
在这里插入图片描述

对于无符号数来说,最大的数就是

(2^8 - 1)

那怎么表示负数呢?牺牲最高位作为符号位,符号位为 1,则为负数;如果为 0,则为正数。,这便是原码

这样就能得到以下分类:

在这里插入图片描述
在这里插入图片描述

符号位后两个极端,全0或者全1,正数可以表达

2^7

个,负数也可以表达

2^7

个,但是出现一个问题:0被重复表达了两次!+0和-0,所以,原码表示法出现了缺陷:

  • 0的表示并不唯一,计算机是机器,不是人,无法理解多义的表达
  • 加法、减法的运算方式并不统一,减法需要借位,逻辑复杂

所以,引入补码

3.2. 补码表示法

3.2.1 模运算的引入

对于一个钟表,假定指针指向了10点的位置,我现在要将其拨到6点位置,有两种方式:

  • 倒拨四格:
10 - 4 = 6
  • 顺拨八格:
10 + 8 ———>6

,转完了一圈,18 % 12 = 6

在这里插入图片描述
在这里插入图片描述

钟表是一个模十二的系统:那么就可以理解为

10-4 = 10+8 = 10+(12-4)

这里的-48是相等的关系,那么就可以说8的补码是-4,同样的,9的补码是-3

在模十二的系统中,都遵循着一个原则:互为补码的两个数,不管符号,相加和为12,8+4,9+3,10+2的结果都是12

那么,在一个模

x

的运算系统中,有两个数

1

-n

,一定满足

1+n=x

那么就引出了补码的运算:加法和减法的运算逻辑相同

如果做减法,我们只需要加上这个数的补码即可,将减法转换成了加法,这样加减法共用一套逻辑

3.2. 补码表示法

**”8位2进制数“模运算系统(mod

2^8

)**中,有两个数

1

-n

,一定满足

1+n=2^8

现在用

2^8

减去一个1,即是

1 0000 0000 - 0000 0001————> 得到1111 1111,这个数,是-1的表达,所以-1的表达,就是

2^8

减去1,相当于把原来的0000 0001各位取反再加1————>1111 1111,现在使得1111 1111 + 0000 0001————>1 0000 0000即是

2^8

,这便是负数的补码

正数的补码是正数本身,负数的补码是符号位不变,其他位取反,末位加一

例如:-1:原码1000 0001 补码:1111 1111

现在回到之前的分类:

在这里插入图片描述
在这里插入图片描述

这样原来的-0:1000 0000就可以表示一个更小的数了

我们再将1000 0000转换成原码检查一下:

除了符号位全部取反->1111 1111,末尾+1->1 0000 0000,

八位存不下,最高位截断:0000 0000 ->0

0 + 2^8 = 2^8

,满足“8位2进制数“模运算系统(mod

2^8

)的规则

以下是常见整型的取值范围:

在这里插入图片描述
在这里插入图片描述

我们可以继续用一个圆来理解:

在这里插入图片描述
在这里插入图片描述

short int等其他类型同理

4. 小案例

4.1. 规定:若运算中同时有无符号和带符号整数,则按无符号整数运算

关系运算符

类型

结果

说明

0 == 0U

无符号

1

同为零

-1 < 0

有符号

1

有符号类型-1<0

-1 < 0U

无符号

0

11…11( 2 32 − 1 2^{32}-1 232−1) > 0

2147483647 > -2147483647 -1

有符号

1

正数 >负数

2147483647U > -2147483647 - 1

无符号

0

01…1( 2 31 − 1 2^{31}-1 231−1)<10…0( 2 31 2^{31} 231)

2147483647 >(int)2147483647U

有符号

1

01…1( 2 31 − 1 2^{31}-1 231−1)>10…0( − 2 31 -2^{31} −231)

-1 >-2

有符号

1

有符号类型-1>-2

(unsigned)-1 > -2

无符号

1

11…11( 2 32 − 1 2^{32}-1 232−1) > 11…10( 2 32 − 2 2^{32}-2 232−2)

2^{32}-1

) > 02147483647 > -2147483647 -1有符号1正数 >负数2147483647U > -2147483647 - 1无符号001…1(

2^{31}-1

)<10…0(

2^{31}

)2147483647 >(int)2147483647U有符号101…1(

2^{31}-1

)>10…0(

-2^{31}

)-1 >-2有符号1有符号类型-1>-2(unsigned)-1 > -2无符号111…11(

2^{32}-1

) > 11…10(

2^{32}-2

)

对于intunsigned int

2^{31}-1 > -2^{31}
在这里插入图片描述
在这里插入图片描述

4.2. 计算机的世界只有0和1,具体怎么解读靠人的定义

代码语言:javascript
复制
int main() {
	int x = -1;
	unsigned u = 2147483648;
	printf("x = %u = %d\n", x, x);
	printf("u = %u = %d\n", u, u);

	return 0;
}
  1. 对于变量 x = -1
    • 在内存中,-1 作为 32 位有符号整数(补码)存储为全 1:11111111 11111111 11111111 11111111
    • 当用 %u(无符号整数格式)输出时,这个二进制被解读为无符号数,值为 4294967295(2³²-1)
    • 当用 %d(有符号整数格式)输出时,正确解读为 -1
  2. 对于变量 u = 2147483648
    • 作为无符号整数,它的二进制是 10000000 00000000 00000000 00000000
    • 当用 %u 输出时,正确显示为 2147483648
    • 当用 %d 输出时,这个二进制被解读为有符号整数(补码),由于最高位是 1(符号位),表示这是一个负数。在 32 位有符号整数中,这个值恰好是最小的负数 -2147483648
在这里插入图片描述
在这里插入图片描述

这个例子展示了C/C++整数的二进制存储本质:相同的二进制序列,根据解释方式(有符号 / 无符号)的不同,会呈现出完全不同的数值。格式化字符 %d%u 决定了如何解读内存中的二进制数据,而不是改变数据本身。

代码语言:javascript
复制
int main() {
	int b = -1;
	char c = -1;
	printf("%u,%u\n",b, c);

	return 0;
}
  1. 变量存储分析
    • int b = -1:作为 32 位有符号整数,-1的补码表示为全 1(11111111 11111111 11111111 11111111
    • char c = -1:在大多数系统中char是 8 位,-1的补码表示为11111111
  2. printf输出规则
    • 当使用%u(无符号整数格式)输出时,所有整数类型都会被提升为unsigned int
    • b作为 int 直接转换为 unsigned int,全 1 的 32 位二进制对应4294967295
    • c作为 char 首先进行符号扩展(因为是有符号 char),8 位的11111111扩展为 32 位的11111111 11111111 11111111 11111111,再转换为 unsigned int 也得到4294967295
    在这里插入图片描述
    在这里插入图片描述

这个例子展示了C/C++整数提升符号扩展的规则:当小整数类型参与表达式运算或格式化输出时,会先提升为 int (有符号扩展),再根据格式控制符进行相应转换。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1. int类型变量的声明、定义、赋值
  • 1.2. 未初始化的变量
  • 2. 其他的整型
    • 有符号和无符号数
  • 3. 整型数据的存储
    • 3.1. 原码表示法
    • 3.2. 补码表示法
      • 3.2.1 模运算的引入
      • 3.2. 补码表示法
  • 4. 小案例
    • 4.1. 规定:若运算中同时有无符号和带符号整数,则按无符号整数运算
    • 4.2. 计算机的世界只有0和1,具体怎么解读靠人的定义
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档