美文网首页
原码、反码、补码 ,10000000 = -128

原码、反码、补码 ,10000000 = -128

作者: ag4kd | 来源:发表于2019-10-23 14:10 被阅读0次

    一 clang 分四步编译main.c

    这里用的clang/clang++ 分四步编译main.c/main.cpp文件

    1.1 C++源文件

    #include <iostream>
    
    int main() {
        std::cout << "Hello Biter !" << std::endl;
        return 0;
    }
    
    -c600
    -c600
    -c600

    1.2 预处理、编译、汇编、链接

    clang或者clang++方式
    <div STYLE="page-break-after: always;"></div>

    1.2.1 预处理

    命令:

    clang++ -E main.cpp -o main.ii

    -c400

    <div STYLE="page-break-after: always;"></div>

    1.2.2 编译阶段,生成汇编

    clang++ -S main.ii -o main.s 
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    1.2.3 汇编阶段,生成目标文件

     clang++ -c main.s -o mian.o
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    1.2.4 连接阶段

     clang++ mian.o -o main
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    1.2.5 执行

     ./main
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    1.3 四部曲之一步到胃

    clang++在编译的过程中,保存所有编译过程中产生的文件

    1.3.1 产生中间文件

     clang++ -save-temps main.cpp -o main
    
    -c400

    1.3.2 不保存中间文件

     clang++  main.cpp -o main
    

    <div STYLE="page-break-after: always;"></div>

    二 持有ndk的交叉编译工具 编译main.c

    2.1 预处理

    armv7a-linux-androideabi29-clang++ -E main.cpp -o main.ii
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    2.2 编译

     armv7a-linux-androideabi29-clang++ -S main.ii -o main.s
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    2.3 汇编

    armv7a-linux-androideabi29-clang++ -c main.s -o mian.o
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    2.4 连接

    armv7a-linux-androideabi29-clang++ mian.o -o main
    
    -c400

    <div STYLE="page-break-after: always;"></div>

    3 原码、反码、补码

    3.1 知识点补充

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

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

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

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

    原码即直接将真值转换为其相应的二进制形式,而反码和补码是对原码进行某种转换编码方式。

    正整数原码反码补码都一样。

    负数的反码是对原码的除符号位外的其他位进行取反后的结果(取反即如果该位为0则变为1,而该位为1则变为0的操作)。而补码是先求原码的反码,然后在反码的末尾位加1 后得到的结果,即补码是反码+1。

    IBM-PC中带符号整数都采用补码形式表示。

    <font color="brown">注意,只是带符号的整数采用补码存储表示的,浮点数另有其存储方式。</font>

    1. 正数的补码是其本身
    2. 负数的反码,符号位不变,其余的按位取反
    3. 负数的补码,反码加1

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

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

    机器码组合 范围 个数
    0000 0000 - 0111 1111 0 ~+127 128
    <font size="3" color="brown">10000000 </font> 多余的一种组合待定 1
    1000 0001 - 1111 1111 -1~-127 127

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

    <div STYLE="page-break-after: always;"></div>
    从大到小,依次减1看一下规律:

    十进制 (字长8bit) 原码 反码 补码
    127 0111 1111 0111 1111 0111 1111
    126 0111 1110 0111 1110 0111 1110
    …… …… …… ……
    10 0000 1010 0000 1010 0000 1010
    …… …… …… ……
    2 0000 0010 0000 0010 0000 0010
    1 0000 0001 0000 0001 0000 0001
    +0 0000 0000 0000 0000 0000 0000
    -1 1000 0001 1111 1110 1111 1111
    -2 1000 0010 1111 1101 1111 1110
    …… …… …… ……
    -10 10001010 11110101 11110110
    …… …… …… ……
    -127 11111111 10000000 10000001
    待定 <font size="3" color="brown">10000000 </font> <font size="3" color="brown">10000000 </font> <font size="3" color="brown">10000000 </font>

    从递减规律中,发现,<font size="3" color="brown">10000000 </font>表示-128更合适。

    即规定:-128的补码为 <font size="3" color="brown">10000000 </font>

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

    十进制 (字长8bit) 原码 反码 补码
    10 00001010 00001010 00001010
    -10 10001010 11110101 11110110
    -1 1000 0001 1111 1110 1111 1111
    +0 00000000 00000000 00000000
    -0 <font size="3" color="brown">10000000 </font> 11111111 00000000
    -128 <font size="3" color="brown">10000000 </font>
    127 01111111 01111111 01111111
    -127 11111111 10000000 10000001

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

    <div STYLE="page-break-after: always;"></div>

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

    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的无符号十六进制整数
    %% 打印一个百分号

    <div STYLE="page-break-after: always;"></div>

    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"

    <div STYLE="page-break-after: always;"></div>

    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;

    4.4.1 结论

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

    1、<font color="brown">正数的原码的反码、补码是其本身,扩展时,高位补0;</font>

    2、<font color="grey">负数扩展为有符号的高位补1,无符号的高位补0。</font>

    2、<font color="brown" size=3px >负数扩展时,高位补 1。格式化输出无符号的数据时,机器码即为原码;格式化输出有符号数据时,要先求其原码,然后求得真值。</font>

    c 的机器码为10000000

    4.4.2 输出32位有符号int:

    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

    <font color="brown">有符号,其值为:-128.</font>

    4.4.3 输出8位有符号signed char:

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

    8位机器码:1000 0000

    <font color="brown">此机器码没有反码和源码,机器码即为真值:-128.</font>

    4.4.4 输出16位有符号 short int

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

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

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

    <font color="brown">有符号,其值为:-128.</font>

    4.4.5 输出16位无符号 short int

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

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

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

    原码:1111 1111 1000 0000

    <font color="brown">做无符号运算,其值:65408</font>

    4.5 源码

    #include <iostream>
    #include <bitset>
    
    int main() {
        using namespace std;
        cout << "Hello Biter !" << endl;
        char c = 128;
        cout << "---------------- -" << int(c) << "-----------------------  " << endl;
        cout << "char 型 机器码 =  " << bitset<sizeof(char) * 8>(c) << endl;
        cout << "int 型 机器码 =  " << bitset<sizeof(int) * 8>(c) << endl;
        cout << "signed char 型 机器码 =  " << bitset<sizeof(signed char) * 8>(c) << endl;
        cout << "short int 型 机器码 =  " << bitset<sizeof(short int) * 8>(c) << endl;
        cout << "unsigned short int 型 机器码 =  " << bitset<sizeof(unsigned short int) * 8>(c) << endl;
        cout << "char 二进制形式为 =  " << bitset<sizeof(char) * 8>(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;
    }
    

    相关文章

      网友评论

          本文标题:原码、反码、补码 ,10000000 = -128

          本文链接:https://www.haomeiwen.com/subject/kuckvctx.html