c语言的整型和字符型数据类型可以分为有符号型和无符号型,无符号类型在定义时于关键字前标明unsigned。由于无符号类型没有负号,数据最小值为0。
计算机存储信息的最小单位,称之为位(bit,又叫比特),其计量基本单位是字节(Byte 简称B),8个二进制位称为1个字节,8bit = 1byte。
不同的数据类型所占字节数不同,可以通过sizeof()运算符(在c语言中sizeof为运算符而非函数)打印出不同整型类型所占内存字节数。
#include <stdio.h>
int main()
{
printf("char所占字节数:%d\n",sizeof(char));
printf("short所占字节数:%d\n", sizeof(short));
printf("int所占字节数:%d\n", sizeof(int));
printf("long所占字节数:%d\n", sizeof(long));
printf("long long所占字节数:%d\n", sizeof(long long));
return 0;
}
如何通过控制台打印出int、 short 、char 、long long等类型的数据范围
这里需要引入原码反码和补码的概念:计算机中对数字的二进制定点表示需要通过原码、反码和补码。
十进制数据的二进制表达就是原码,原码最左侧的第一个数字是符号位,数字0为正,数字1为负。
将正数5用原码表示为:
将负数5用原码表示为:
正数5的第一位符号位为0,代表正数,负数5的第一位符号位为1,代表负数。
正整数的原码,反码和补码相同都为十进制的二进制表现。
负数的反码为:在原码的基础上,第一位符号位不变,后面的真值位取反(0变成1,1变成0)。
负数5的反码表示为(第一行为-5的原码,第二行为-5的反码):
负数的补码为:在反码的基础上,最后+1。
负数5的补码表示为(第一行为-5的反码,第二行为-5的补码):
由于计算机不能进行减法,所以补码的引入能够使减法成为可能,即a-b = a+(-b)
在计算机进行二进制加法时,将会按照补码的计算方式
例如:计算16 - 5 =?
机器码会将这个问题转化为16 + (-5) = ?
16的补码和原码相同,为:
-5的补码需要先从原码计算:
原码:
原码的第一位符号位不变,其余取反为反码 :
反码的最后+1为补码 :
然后将16和-5的补码相加即可得出16-5的值:
最后得:00001011(第一位1被溢出舍弃)
将00001011由二进制转化为十进制为:
刚好就是16-5的答案为11。计算机通过补码的方式巧妙地将减法化为加法,计算出了最终的答案。
-1的补码为1111 1111 1111 1111,是四字节存储的最大值,由此可以打印出int、 short 、char 、long long等类型的数据范围。
通过定义无符号变量的值为-1,通过补码计算由无符号角度可以输出不同数据类型的数据范围(由于-1为最大值,利用溢出现象通过对-1补码可以计算数据类型的数据范围)
#include <stdio.h>
int main()
{
unsigned char a = -1;
unsigned short b = -1;
unsigned int c = -1;
unsigned long d = -1;
unsigned long long e= -1;
printf("char:\t\t0~%hhu 最大值:%hhd 最小值:%hhd\n", a, a / 2, a / 2 + 1);
printf("short:\t\t0~%hu 最大值:%hd 最小值:%hd\n", b, b / 2, b / 2 + 1);
printf("int:\t\t0~%u 最大值:%d 最小值:%d\n", c, c / 2, c / 2 + 1);
printf("long:\t\t0~%lu 最大值:%ld 最小值:%ld\n", d, d / 2, d / 2 + 1);
printf("long long:\t0~%llu 最大值:%lld 最小值:%lld\n", e, e / 2, e / 2 + 1);
return 0;
}
在二进制的计算中,值除以二即为二进制数向后一位,比如255的二进制为1111 1111
255的一半取整127的值用二进制表示为0111 1111.
机器码的计算:
也可: