补码原理

1、补码

 

//嵌入式开发需要了解补码

#include<stdio.h>

void main(){
    
    int a = -1;  //-1 在int 范围内,赋值实际上是赋的内存地址中二进制的值
    printf("%x\n",&a);  //&a的内存地址是0x0018FA88通过改地址找到内存中的值是ff ff ff ff
    /* -1 内存中的值为 ff ff ff ff 
        -1的补码二进制为:1111 1111  1111 1111 1111 1111 1111 1111
        -1的反码二进制为:1111 1111  1111 1111 1111 1111 1111 1110    -1
        -1的原码二进制为:1000 0000  0000 000  0000 0000 0000 0001   取反
    */
    printf("%d,%u\n",a,a); //output: -1,4294967295
    /*%d按照有符号的十进制输出,-1在[-2^15,2^15-1]内,内存中二进制的补码值为1111 1111  1111 1111 1111 1111 1111 1111,
    首位1代表符号位,求出其原码,1000 0000  0000 000  0000 0000 0000 0001,输出-1,
    %u按照无符号的十进制输出,-1不在[0,2^32-1]内,但-1的内存中二进制的补码值为1111 1111  1111 1111 1111 1111 1111 1111
    无符号位,正数的原码与补码一样,求出其原码 1111 1111  1111 1111 1111 1111 1111 1111,输出4294967295,*/


    int b = 4294967295;  //4294967295不在int范围内,直接把二进制赋值给b,有系统声明的变量去做解析和解释
    //4294967295的二进制形式为:1111 1111  1111 1111 1111 1111 1111 1111
   //把上面的二进制直接赋值给b,printf()函数的本质是按照指定格式%d或%u输出二进制的值,不管二进制是什么数
    //%d按照有符号的十进制整数去解析输出就是-1,%u按照无符号十进制的整数输出4294967295
    printf("%d,%u\n", b, b); //output: -1,4294967295

    unsigned int c = -1;  //-1 不在unsigned int 范围内
    unsigned int d = 4294967295; // 4294967295在unsigned int 范围内
    /* 数据复制本质上是二进制的赋值,数据范围内保证正确,数据范围外不保证正确
    4294967295的内存中的二进制形式为:1111 1111  1111 1111 1111 1111 1111 1111
         -1        内存中的二进制形式为:1111 1111  1111 1111 1111 1111 1111 1111
    两个数在内存中存储的二进制是一样的,在程序运行时,按照各自声明的变量进行解析
    c尽管是无符号整型,没有负数,但按%d有符号解析,32位1转换成原码就是-1,输出-1
                            按%u解析,也是无符号的,32位都是数据位,输出4294967295
    d尽管是无符号整型,没有负数,但是按%d有符号解析,32位1转换成原码就是-1,输出-1
                            按%u解析,也是无符号的,32位都是数据位,输出4294967295
    */
    printf("%d,%u\n", c ,c);//output: -1,4294967295
    printf("%d,%u\n", d, d);//output: -1,4294967295


    //以下内容没有搞懂,以后再看
    int e = 217483648;   //217483648 不在int范围内
    /*2147483647的内存中的二进制形式为:0111 1111  1111 1111 1111 1111 1111 1111 最大值
      2147483648的内存中的二进制形式为:1000 0000  0000 0000  0000 0000 0000 0000
      1、%d解析 带符号解析
    补码  2147483648的内存中的二进制形式为:1000 0000  0000 0000  0000 0000 0000 0000  也就是补码 首位1表示该数是负数
     反码 2147483648的内存中的二进制形式为:1111 1111  1111 1111  1111 1111 1111 1111 减去1,符号位不变 首位1表示该数是负数
     原码  2147483648的内存中的二进制形式为:1000 0000  0000 0000  0000 0000 0000 0000  取反 符号位不变 首位1表示该数是负数
    */
    printf("%d,%u\n", e, e);//output:-2147483648,2147483648
    int f = -217483648;   //-217483648 不在int范围内
    printf("%d,%u\n", f, f);//output:-217483648, 4077483648

    char h = 255;   //-255 不在char范围内
    printf("%d,%u\n", h, h);//output:-217483648, 4077483648
    /*
      1111 1111

    结论:赋值和解析是分开的,赋值的本质是赋二进制的值,解析按照%d,%u去解析
    */
    getchar(); 
}

 

  %d是有符号整型输出 有范围限制,INT_MIN-INTMAX   

%u是无符号整型输出 有范围限制,0-UINTMAX   

按照%d解析

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
void main(){
	
	printf("%d,%u", UINT_MAX, UINT_MAX); //-1,4294967295
	/* UINT_MAX  1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	 按照%d解析  1111 1111  1111 1111  1111 1111  1111 1111  1111 1110
		 1000 0000  0000 0000  0000 0000  0000 0000  0000 0001   原码是  -1
	*/
	system("pause");

}

 同样的二进制数值存储形式,不同的解析方法,其结果也会不一样

//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void main(){
	int x = 4294967295;  //4294967295已经超过了int的范围
	//赋值本质上是赋值二进制的值,即使该数已经超过了其表示范围,所以是直接把数值在计算机的表现形式(补码的形式)赋值给&x,
	//4294967295内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//按照%d解析,有符号解析,首位1代表负数,内存中的二进制则是负数的存储形式,负数在内存中是以补码的形式存放
	//得转换成程序中的原码形式:
	// 符号位不变,-1成 反码 1111 1111  1111 1111  1111 1111  1111 1111  1111 1110
	//符号位不变,取反成原码 1000 0000  0000 0000  0000 0000  0000 0000  0000 0001
	//即为-1;
	//按照%u来解析,内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//首位不是符号位,都是数值位,即是4294967295
	printf("%d,%u",x,x); //-1,4294967295

	int y = -1;  
	//赋值本质上是赋值二进制的值,所以是直接把数值在计算机的表现形式(补码的形式)赋值给&y,
	//-1内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//  按照%d和%u解析,同以上原理一样。
	printf("%d,%u", x, x); //-1,4294967295
	//内存中同样的二进制,解析不一样,结果也会不一样
	system("pause");
}

 无符号int也一样

//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void main(){
	unsigned int x = 4294967295;  
	//赋值本质上是赋值二进制的值,所以是直接把数值在计算机的表现形式(补码的形式)赋值给&x,
	//4294967295内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//按照%d解析,有符号解析,首位1代表负数,内存中的二进制则是负数的存储形式,负数在内存中是以补码的形式存放
	//得转换成程序中的原码形式:
	// 符号位不变,-1成 反码 1111 1111  1111 1111  1111 1111  1111 1111  1111 1110
	//符号位不变,取反成原码 1000 0000  0000 0000  0000 0000  0000 0000  0000 0001
	//即为-1;
	//按照%u来解析,内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//首位不是符号位,都是数值位,即是4294967295
	printf("%d,%u",x,x); //-1,4294967295

	unsigned int y = -1;  
	//赋值本质上是赋值二进制的值,即使该数已经超过了其表示范围,所以是直接把数值在计算机的表现形式(补码的形式)赋值给&y,
	//-1内存中的存储形式:1111 1111  1111 1111  1111 1111  1111 1111  1111 1111
	//  按照%d和%u解析,同以上原理一样。
	printf("%d,%u", x, x); //-1,4294967295
	//内存中同样的二进制,解析不一样,结果也会不一样
	system("pause");
}

 

/*
short int(long) long long
%hd %d %lld


%d 无符号10进制 10 10
%o 无符号8进制 010 8
%x 无符号16进制 0x10 16

%d —— 以带符号的十进制形式输出整数
%o —— 以无符号的八进制形式输出整数
%x —— 以无符号的十六进制形式输出整数
%u —— 以无符号的十进制形式输出整数
%c —— 以字符形式输出单个字符
%s —— 输出字符串
%f —— 以小数点形式输出单、双精度实数
%e —— 以标准指数形式输出单、双精度实数
%g —— 选用输出宽度较小的格式输出实数
*/
posted @ 2019-07-21 14:21  Coding_Changes_LIfe  阅读(655)  评论(0编辑  收藏  举报