补码原理
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 —— 选用输出宽度较小的格式输出实数
*/