• 一个小问题引出的


    在看C专家编程,遇到一段代码:

    #include <stdio.h>
    
    int array[] = {1,2,3,4,5,6,6};
    #define TOTAL_ELEMENTS (sizeof(array))/sizeof(array[0])
    
    int main()
    {
        int d = -3;
        int x = -3;
            
        if(d <= TOTAL_ELEMENTS - 2)
        {
            x = array[d + 3];
        }
    
        return 0;
    }

    这里的本意显然是要给x赋值,但实际上却不会进到这里,这里引出了2个问题:

    1.TOTAL_ELEMENTS的类型

    sizeof返回值的类型为size_t,而typedef unsigned int size_t,所以TOTAL_ELEMENTS - 2的类型为unsigned int.

    这里引出第二个问题

    2.类型转换

    d的类型为int,这里的比较就涉及到类型转换了,一般都是低级向高级转换,而低级向高级转换的序列大致为

    short,char ---> int -----> unsigned int ---> float ---> double  <--- long

    所以这里d会提升数据类型,即-3转换成(unsigned)-3,其实这里的-3在字节层面并未改变,只是从之前的有符合类型,现在解释为无符号类型,

    -3的二进制表示为 -3 = -1 - (2) = 0xffff ffff -(2) = 0xffff fffd

    现在解释为无符号数自然是个很大的数,所以不会进行赋值操作了。

    到这里自然而然会想到数据的编码问题

    一:整数的编码

    1.无符号编码

    这个很简单,比如10 = 1010,扩展为32位就是0000 0000 0000 1010.

    2.有符合编码

    这个比较麻烦了,比如-10,这个怎么表示呢?

    先给出一个比较快捷的方式,那就是-10 = 1- - (9)。然后问题就转换为-1的二进制表示究竟是怎样的?

    先给出如下一个事实:

    -1 = 0x11

    -1 = 0x111

    -1 = 0x1111

    -1 = 0x11111

    ...

    -1 = 0xffff ffff

    也就是说不管机器是多少位,0x111..1都是表示-1.

    在这个基础之上,负数的二进制表示就方便了,一律通过-1来求,比如:

    -10 = -1 - 9 = 0xffff ffff - 9 = 0xffff fff6

    如果你不太放心,再提供另外一个方法进行检验结果:

    0xffff fff6 = 0x1111 1111 1111 1111 1111 1111 1111 0110 = -1 * 2 exp (31) + 1 * 2 exp(30) + ... + 1 * 2 exp(2) + 1 * 2 exp(1) + 0 * 2 exp(0) = -10

    如上,每个位上都有对应的权重,即使带小数点,这个权重也是适用的,只不过权重变为exp(-1),exp(-2)...

    二.浮点数(实数、带小数点)编码

    浮点数比较复杂,主要通过举例来讲解,首先给出32体系下浮点数的分布情况

    例一:

    12.25

    第一步:这是一个正数,所以31位是0

    第二步:转换成二进制表示,1100.01

    第三步:转换成科学表示法,必须以1.开头,即1.10001 * 2 exp(3)

    第四步:计算指数部分,3 + 127(这地方的127表示指数偏移基数,32位的指数基数为127,64位为1023,这个也不用纠结) = 130 = 1000 0010

    第五步:计算小数点后面的,貌似也叫尾数,同样的叫啥不重要,10001,不足23位的右补0

    所以最后在机器中的二进制表示为0 1000 0010 10001 000000000000000000

    十六进制表示为0x4144 0000

    给出验证代码:

    #include <stdio.h>
     
     int main()
     {
         float a = 12.25;
     
         int* p = (int*)&a;
         printf("%#x
    ", *p);
     
         return 0;
     }

    例二:

    -12.25

    与例一唯一区别就是31位的符号为1,所以结果为0xc144 0000

    例三:

    10.3

    这个与上面的是会有区别的地方是转换成二进制的时候,是无穷的,

    第一步:这是一个正数,所以31位是0

    第二步:转换成二进制表示,主要是0.3的二进制表示,

      0.3 0.6 0.2 0.4 0.8 0.6 ...

                0    1   0    0    1  ...

    直到填满23位,最终表示为1010.010011 0011 0011 0011 0011 0

    第三步:转换成科学表示法,必须以1.开头,即1.010010011 0011 0011 0011 0011 0 * 2 exp(3)

    第四步:计算指数部分,3 + 127 = 130 = 1000 0010

    第五步:计算小数点后面的,010010011 0011 0011 0011 00 11 0

    这里26位了怎么处理呢?难道要进位,从而是010010011 0011 0011 0011 01??试试呢,这样的话

    最后在机器中的二进制表示为0 1000 0010 010010011 0011 0011 0011 01

    十六进制表示为0x4124cccd,用上面的程序验证,竟然对了!!!

  • 相关阅读:
    git生成SSH秘钥
    ifconfig
    接口自动化测试平台:简介
    Gitd的使用
    jenkins自动化部署和Tomcat中间件容器
    Struts2——用来开发 MVC 应用程序的框架,可用于创建企业级Java web应用程序
    Hibernate——Java 领域的持久化ORM框架
    jQuery——JavaScript库
    JavaScript HTML DOM——文档对象模型
    JVM 完整深入解析
  • 原文地址:https://www.cnblogs.com/seeken/p/5486654.html
Copyright © 2020-2023  润新知