一个小问题引出的

在看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,用上面的程序验证,竟然对了!!!

原文地址:https://www.cnblogs.com/seeken/p/5486654.html