位扩展详解

来源:互联网 发布:golang selenium爬虫 编辑:程序博客网 时间:2024/04/20 12:43
 

首先要知道我们的数据是怎么样放入内存的,例如我们int a=2;sizeof(int)=2;那么放入内存的数据为00000000 00000010,假设int a=-2,那么存放为11111111 11111110,始终记住在内存里存放的是补码形式,正数的补码是本身。现在要用printf输出,就先要到内存里面去得到数,假设%d形式输出,则函数根据符号为进行求源码,如果是%u输出则函数认为内存里存放的为无符号数,所以直接输出数字11111111 11111110=65534。

       假设我们把一个int赋给char的,那么int 就要被截断了,底8位不动的直接挪给char,例如unsigned char c;

C=a;那么c对应的内存为11111110(当a=-2),当我们输出格式为%d,%u的时候都是254哦,这和unsigned int a=-2不一样,当我们输出格式为%d,%u的时候一个正数,一个负数。

       假设我们相反把一个char赋给int,那么就要进行符号扩展了,谭书上60页说了:

如果把字符处理为无符号的,那么int的高位全部补0;

如果把字符处理为有符号的,那么int的高位与char放在内存的数据的最高为扩展,例如char c=-2,在内存里面格式为11111110,那么int a=c,a的格式为11111111 11111110,如果char c=2,在内存的存放为00000010,那么int a=c,a的格式为00000000 00000010

记住printf的格式控制是从内存里面取数据,在进行相应的转换的

2

       当我们输入数据的时候假设int a=2,那么内存里面高位扩0,但是如果int a=65535,那么16为已经满了它不会写成0 11111111 11111111因为这样已经17位了

一个符号扩展的例子:

typedef struct {

        int a:2;  1

        int b:2;  2

        int c:1;  3

     }test;

     test t;

     t.a = 1;     4

     t.b = 3;     5

     t.c = 1;     6

     printf("%d",t.a);   7

     printf("%d",t.b);   8

     printf("%d",t.c);   9

     谢谢!

t.a为01,输出就是1

t.b为11,输出就是-1

t.c为1,输出也是-1   ---位扩展

解释:a不说,对于b来说,t.b=3,写进内存为11,因为已经满2位了,所以直接进驻内存,不用扩展符号,(不考虑补码的形式),但printf输出的是int型,所以要进行到2到16位的扩展,因为申明的是int b:2;所以高16位字节与b的最高位一样为111111111 11111111,所以输出为%d的形式输出为-1,如果%u的形式,那么输出为65535.

假设我们在第2行中把int b:2,写成unsigned int b:2,那么结果就变了哦,这就导致了进行符号扩展的时候全部补0,结果是在内存的格式就是00000000 00000011输出的两种都为3.

负数的补码

  符号位为1,其余位为该数绝对值的原码按位取反;然后整个数加1。
  同一个数字在不同的补码表示形式里头,是不同的。比方说-15的补码,在8位2进制里头是11110001,然而在16位2进制补码表示的情况下,就成了1111111111110001。在这篇补码概述里头涉及的补码转换默认了把一个数转换成8位2进制的补码形式,每一种补码表示形式都只能表示有限的数字。
  【例2】求-7的补码。
  因为给定数是负数,则符号位为“1”。
  后七位:+7的原码(0000111)→按位取反(1111000)→加1(1111001)
  所以-7的补码是11111001。
  已知一个数的补码,求原码的操作分两种情况:
  (1)如果补码的符号位为“0”,表示是一个正数,其原码就是补码。
  (2)如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
  再举一个例子:求-64的补码
  +64:01000000
  11000000
  【例3】已知一个补码为11111001,则原码是10000111(-7)。
  因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。
  其余七位1111001取反后为0000110;
  再加1,所以是10000111。