原码反码补码

3.1 知识点补充

在计算机内部,所有信息都是用二进制数串的形式表示的。整数通常都有正负之分,计算机中的整数分为无符号的和带符号的。无符号的整数用来表示0和正整数,即自然数;带符号的正数可以表示所有的整数。

由于计算机中符号和数字一样,都必须用二进制数串来表示,因此,正负号也必须用0、1来表示。通常我们用最高的有效位来 表示数的符号(当用8位来表示一个整数时,第8位即为最高有效位,当用16位来表示一个整数时,第16位即为最高有效位。)0表示正号、1表示负号。

这种正负号数字化(0表示正号、1表示负号)的机内表示形式就称为 机器码或者 机器数,而相应的机器外部用正负号表示的数称为 真值。将一个真值表示成二进制字串的机器数的过程就称为 编码

无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。带符号整数有原码、反码、补码等几种编码方式。

原码即直接将真值转换为其相应的二进制形式,而反码和补码是对原码进行某种转换编码方式。正整数的原 码、反码和补码都一样,负数的反码是对原码的除符号位外的其他位进行取反后的结果(取反即如果该位为0则变为1,而该位为1则变为0的操作)。而补码是先求原码的反码,然后在反码的末尾位加1 后得到的结果,即补码是反码+1。IBM-PC中带符号整数都采用补码形式表示。

注意,只是带符号的整数采用补码存储表示的,浮点数另有其存储方式。

对于字长为8位有符号的int,因为最高为符号位,占1位,所以最小为(1111111)2 = (-127)10,最大为(0111111)2 = (127)10;即其原码范围为:-127~127

有符号的8位二进制的原值表达范围为:-127至127,此时共255个数字;然而,8位二进制 的补码排列共有$A_{2}^{8}$ = 256个,0000 0000 至1111 1111 。

补码组合 范围 个数 0000 0000 – 0111 1111 0 ~+127 128 10000000 多余的一种组合待定 1 1000 0001 – 1111 1111 -1~-127 127

10000000 看似要被浪费掉了啊!其实不然,( 100000000 ) 2 = ( 2^7 ) 10 = ( 128 ) 10,这个组合要利用起来,不能太偏离数值意义,表示128,显得更直观。

从大到小,依次减1看一下规律: 十进制 (字长8bit) 原码 反码 补码

0111 1111 0111 1111 0111 1111

0111 1110 0111 1110 0111 1110

…… …… ……

0000 1010 0000 1010 0000 1010

…… …… ……

0000 0010 0000 0010 0000 0010

0000 0001 0000 0001 0000 0001

0000 0000 0000 0000 0000 0000

1000 0001 1111 1110 1111 1111

1000 0010 1111 1101 1111 1110

…… …… ……

10001010 11110101 11110110

…… …… ……

11111111 10000000 10000001

10000000 10000000 10000000

从递减规律中,发现,10000000 表示 -128更合适。

即规定:-128的补码为 10000000

求10 -10 0 -128 127 的原码、反码、补码

十进制 (字长8bit) 原码 反码 补码

00001010 00001010 00001010

10001010 11110101 11110110

1000 0001 1111 1110 1111 1111

00000000 00000000 00000000

10000000 11111111 00000000

无 无 10000000

01111111 01111111 01111111

11111111 10000000 10000001

+0和-0的补码是一样的。即 0的补码只有一种表示,0的补码是 0000 0000,

四 输出结果,解释为什么是这样的

char c = 128;
printf("%d\n",c);
printf("%hhd\n",c);
printf("%hd\n",c);
printf("%hu\n",c);

4.1 格式输出符

格式符号 意义 %a 浮点数、十六进制数字和p-记数法 (C99) %A 浮点数、十六进制数字和P-记数法 (C99) %c 一个字符 %d 有符号十进制整数 %e 浮点数、e-记数法 %E 浮点数、E-记数法 %f 浮点数,十进制记数法 %g 根据数值不同自动选择%f或者%e。%e格式在指数小于-4或者大于等于精度时使用 %G 根据数值不同自动选择%f或者%E。%E格式在指数小于-4或者大于等于精度时使用 %i 有符号十进制整数 (与%d相同) %o 无符号八进制整数 %p 指针(就是指地址) %s 字符串 %u 无符号十进制整数 %x 使用十六进制数字0f 的无符号十六进制整数 %X 使用十六进制数字0F的无符号十六进制整数 %% 打印一个百分号

4.2 格式输出其修饰符 修饰符 意义 示例 h 和整数转换说明符一起使用,表示一个short int 或者 unsigned short int 类型数值。 “%hd hh 和整数转换说明符一起使用,表示一个signed char 或者unsigned char类型数值。 “%hhd” j 和整数转换说明符一起使用,表示一个intmax_t或uintmax_t值。 “%jd” l 和整数说明符一起使用,表示一个long int 或者unsigned long int 类型值。 “%8lu” ll 和整数说明符一起使用,表示一个long long int或 unsigned long long int 类型值 (C99)。 “%lld” L 和浮点转换说明符一起使用,表示一个long double值。 “%8.4Le” t 和整数转换说明符一起使用,表示一个ptrdiff_t值(与两个指针之间的差相对应的类型) (C99) “%td” – 项目是左对齐的,也就是说,会把项目打印在字段的左侧开始处 “%-20s” + 有符号的值若为正,则显示带加号的符号;若为负,则带减号的符号。 “%+3.2” (空格) 有符号的值若为正,则显示时带前导空格(但是不显示符号);若为负,则带减号符号。+标志会覆盖空格标志。 “% 3.2” # 使用转换说明的可选形式。若为%o格式,则以0开始;若为%x和%X格式,则以0x或0X开始,对于所有的浮点形式,#保证了即使不限任何数字,也打印一个小数点字符。对于%g和%G格式,它防止尾随零被删除。 “%#o” 0 对于所有的数字格式,用前导零而不是用空格填充字段宽度。如果出现-标志或者指定了精度(对于整数)则忽略该标志。 “%010d”

4.3 机器码求解

char c = 128;

此处是将一个 int赋值给一个 char类型变量,进行 隐式类型转换.int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃。

首先,整型128在一个字长为4个字节的的原码为 00000000 00000000 00000000 10000000,当把一个int类型赋值给一个有符号的char类型时,高位被舍弃。实际给 c的是 10000000,此时,被系统认为是一个负数,补码为 10000000,结合上面的分析,其值就是-128

4.4 格式化输出

char c = 128;

先给出通过这次作业得出的一个不完全归纳法结论吧,也是我做出的解释。最后会给出原码验证

1、正数的原码的反码、补码是其本身,扩展时,高位补0;

2、负数扩展为有符号的高位补1,无符号的高位补0。

2、 负数扩展时,高位补 1。格式化输出无符号的数据时,机器码即为原码;格式化输出有符号数据时,要先求其原码,然后求得真值。

c 的机器码为 10000000

printf("%d\n",c);//默认的 int ,32位

1000 0000 转为有符号的32位机器码: 1111 1111 1111 1111 1111 1111 1000 0000

反码: 1111 1111 1111 1111 1111 1111 0111 1111

原码: 1000 0000 0000 0000 0000 0000 1000 0000

有符号,其值为:-128.

printf("%hhd\n",c);//signed char,  8位

8位机器码: 1000 0000

此机器码没有反码和源码,机器码即为真值:-128.

printf("%hd\n",c);//short int,16 位

1000 0000 转为有符号的16位机器码: 1111 1111 1000 0000

反码: 1111 1111 0111 1111 原码: 1000 0000 1000 0000

有符号,其值为:-128.

printf("%hu\n",c);

1000 0000 转为16位机器码: 1111 1111 1000 0000

格式化输出无符号十进制数据,此码即为原码。

原码: 1111 1111 1000 0000

做无符号运算,其值:65408

4.5 源码

#include
#include

int main() {
    using namespace std;
    cout << "Hello Biter !" << endl;
    char c = 128;
    cout << "---------------- -" << int(c) << "-----------------------  " << endl;
    cout << "char 型 机器码 =  " << bitset(c) << endl;
    cout << "int 型 机器码 =  " << bitset(c) << endl;
    cout << "signed char 型 机器码 =  " << bitset(c) << endl;
    cout << "short int 型 机器码 =  " << bitset(c) << endl;
    cout << "unsigned short int 型 机器码 =  " << bitset(c) << endl;
    cout << "char 二进制形式为 =  " << bitset(c) << endl;
    cout << "--------------------------------------------  " << endl;
//    printf("将 char 直接 输出 128 超范围了 = %c\n", c);
//    cout << "--------------------------------------------  " << endl;
    printf("有符号的 int 输出 = %d\n", c);
    cout << "--------------------------------------------  " << endl;
    printf("有符号的 signed char 输出 = %hhd\n", c);//1000,0000
    cout << "--------------------------------------------  " << endl;
    printf("有符号的 short int 输出= %hd\n", c);//0000,0000 1000,0000
    cout << "--------------------------------------------  " << endl;
    printf("无符号的 unsigned short int 输出= %hu\n", c);// 1111,1111 1000,0000
    cout << "--------------------------------------------  " << endl;

    return 0;
}

Original: https://www.cnblogs.com/burner/p/yuan-ma-fan-ma-bu-ma.html
Author: 浪客禅心
Title: 原码反码补码

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/686175/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球