IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [我的C语言学习笔记(03)]补码、unsigned、printf 的格式控制符 -> 正文阅读

[C++知识库][我的C语言学习笔记(03)]补码、unsigned、printf 的格式控制符

补码

补码的概念,存在于整数的存储中,包括 int、short、long、char(由于char是用ASCII码存储在内存中,因此可以看作1字节的整数)等。浮点数的存储思路与整数不同,并且十分复杂,此处不赘述。
有符号的整型变量无论有多少个字节,第一个bit(第一个比特位)都作为符号位存储,0 表示整数,1 表示负数,然后剩下的bit用来存储数据。这里以 int 为例:

符号位数据
1位31位

这样我们可以得到数字的原码。如 int -1 的原码:
10000000 00000000 00000000 00000001
由于计算机底层的加减法计算需要,人们又发明了反码与补码。反码与补码的变化只存在于负数中,整数的原码、反码、补码相同。反码就是除了符号位,剩下的位全部取反。那么 -1 的反码就是:
11111111 11111111 11111111 11111110
而补码就是反码 + 1。可以得到:
11111111 11111111 11111111 11111111
这便是 - 1 在内存中存储的方式。可以用代码验证下:
在这里插入图片描述
可以看到完全正确。
由此我们可以又补码理清整数的存储规律了。以1字节为例:
在这里插入图片描述
这便是1字节整数的取值。注意黄色行,1000 0000是-128,或许联系前后文可以想当然,但是如果我们要去计算它的反码与补码,就会发现计算不出。反码为补码减一,而数据位全为 0,借 1 只能向符号位借,而这是不可理喻的。倘若向符号位借了 1,就会出现这样的结果:
反码:0111 1111
原码:0000 0000
可以看到结果是 0。而原来符号位上是 1,因此是个负数,由此便得到了 -0。而表格的末尾就是 +0 了。这样重复显然是浪费。作为无效值就不如作为特殊值,这样还能多存储一个数字。所以,计算机规定, 1000 0000 这个特殊的补码就表示 -128。
其次,我们再按照“传统”的方法计算一下 -128 的补码:
-128 的数值位的原码是 1000 0000,共八位,而 char 的数值位只有七位,所以最高位的 1 会覆盖符号位,数值位剩下 000 0000。最终, -128 的原码为 1000 0000。
反码:1111 1111。
反码转换为补码时,数值位要加上 1,变为 1000 0000,而 char 的数值位只有七位,所以最高位的 1 会再次覆盖符号位,数值位剩下 000 0000。加上符号位,最终求得的 -128 的补码是 1000 0000。
2字节、4字节、8字节与此大同小异。

unsigned 的使用

unsigned,即无符号,是一个类似short、long 的关键字,在定义变量时修饰,可以使变量的所有位都拿来存储数据。通常用于非负数的存储中,如人数、内存地址等。
如:

unsigned short a = 1;
unsigned int b = 2;//此处int可省略
unsigned long c = 3;

这样就可以增大变量存储的范围。假设原来1字节的变量,由前面的表格可知有符号的范围是-128~ 127,而无符号的范围就变成了0~ 255。
需要注意的是,虽然无符号变量不存储负数,但用负数赋值时仍然需要一个将原码转换成补码的过程,最终存储的仍是一个补码,只不过由于是 unsigned 类型,所以在读取时不用再将补码转换成原码了,而是直接看做原码,且不考虑符号位。
考虑如下实例:

#include <stdio.h>

int main()
{
	unsigned int a = -1;
	
	printf("%x\n", a);
	printf("%u\n", a);
	printf("%d\n", a);

	return 0;
}

在这里我定义一个无符号的变量 a,同时赋值 -1。由于是负数,所以要转换成补码,即 ffff ffff(十六进制)。接下来用代码验证。
在这里插入图片描述
第一个printf 用十六进制打印变量a,可以看到内存中存储的a 确实是-1的补码,再用无符号的形式打印一下,这里的4294967295实际上就是-1补码的十进制。最后用有符号数的打印方式打印,由于是有符号,所以要经历一个由补码到原码的过程,因此又变成了-1。

printf 的格式控制符

在用printf 函数时需要利用格式控制符来打印相应的、不同形式、类型的东西,因此在这里进行汇总。
在这里插入图片描述

联系前面的实例,可以看出,printf 在打印时,若用的是有符号的格式控制符,那么会将内存中的补码转换成原码进行打印;若用的是无符号的格式控制符,那么直接将内存中的补码进行打印。

printf 格式控制符的标准格式:
%[flag][width][.precision]type

说明:
flag:
① -左对齐,若无则右对齐。
② +在输出整数和小数时输出正负号。
③ (空格)在输出整数和小数时为正加上空格,为负加上负号。
④ # 在八进制和十六进制中加上前缀,在小数中(%f/%e/%g)即使没有小数部分也会强制加上小数点。

width:
指定输出长度,不足位以空格补齐,超出则按数据本身长度输出,不起作用。

precision:
表示输出精度,也就是小数的位数。
当小数部分的位数大于 precision 时,会按照四舍五入的原则丢掉多余的数字;当小数部分的位数小于 precision 时,会在后面补 0。
在这里插入图片描述

另外,.precision 也可以用于整数和字符串,但是功能却是相反的:
用于整数时, .precision 表示最小输出宽度。与 width 不同的是,整数的宽度不足时会在左边补 0,而不是补空格。当 precision 大于变量的宽度时要在 n 的前面补0;当precision 小于变量宽度时不再起作用。
在这里插入图片描述

用于字符串时,.precision 表示最大输出宽度,或者说截取字符串。当字符串的长度大于 precision 时,会截掉多余的字符;当字符串的长度小于 precision 时, .precision 就不再起作用。
在这里插入图片描述
顺带说一句,在给整型变量赋值的时候是可以用八进制和十六进制的,如:

int a = 0175;//八进制赋值
int b = 0x9b3f;//十六进制赋值

照例都是要经过一个由原码到补码的过程。如:
在这里插入图片描述

printf 不支持二进制打印,可以用itoa 函数(stdlib.h)将十进制转换成二进制,用字符串存储再打印。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 14:21:50  更:2021-07-10 14:24:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 17:07:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码