整数
符号数:
计算机中的符号数有三种表示方法,即原码,反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位表示方法各不相同。
原码:直接将二进制按照正负数的形式翻译成二进制就可以。
反码:符号位不变,其他位按位取反即可得到。
补码:反码加一得到补码。(在计算机系统中,数值一律用补码来表示和存储。因为使用补码可以将符号位和数值域统一处理)
(正数原反补都相同)
表示方法:(以-1为例)
原码:1000 0000 0000 0000 0000 0000 0000 0001
反码:1111 1111 1111 1111 1111 1111 1111 1110(符号位不变,其它位按位取反)
补码:1111 1111 1111 1111 1111 1111 1111 1111(内存存放形式)
大端模式:数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中。
小端模式:数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
大小端判断:
(1)利用指针强制类型转换
如果是小端方式中,(i至少占两个字节长度)i所分配的内存的最小地址那个字节存着1,;大端的话则1在i的最高地址字节处存放。char是一个字节,所以将char型量p指向i则p指向的一定是i的最低地址,则p指向的一定是i的最低地址,那么就可以判断p中的值是不是1来确定是不是小端。
int main()
{
int a = 1;
char * p = (char*)&a;
if(*p == 1)
{
printf("小端存储");
}
else
{
printf("大端存储");
}
return 0;
}
(2)利用公共体所有数据公用同一块地址空间
联合体地存储顺序是所有成员都从低地址开始存放。
union A
{
char c;
int a;
}A;
int main()
{
A.a = 1;
if(A.c == 1)
{
printf("小端存储");//公用最低一字节,小端返回1
}
else
{
printf("大端存储");
}
return 0;
}
典例分析
(1)
int main()
{
char a = -1; //-1
signed char b = -1; //-1
unsigned char c = -1; //255(没有符号不存在原反补,直接拿出-1的补码转换为二进制数255)
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
(2)
int main()
{
char a = -128; //4294967168
printf("%u\n",a);
return 0;
}
//10000000 00000000 00000000 10000000 原
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000 补
//存的是补码,低八位 10000000
//整型提升 11111111 11111111 11111111 10000000
printf("%u",a); //打印无符号数FFFFFF80
(3)unsigned无符号数造成死循环
由于i为无符号整型,当i=0时,i-1为一个极大的正整数,导致程序陷入死循环
int main()
{
unsigned i;
for(i = 9;i >= 0;i--)
{
printf("%u\n",i);//结果死循环
}
}
同理:
int main()
{
unsigned char i;
for(i = 0;i <= 255; i++)
{
printf("%u\n",i);//结果死循环
}
}
浮点数
先来看一个例子:
num和*pfloat在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?要明白原由一定要搞懂浮点数在计算机内部的表示方法。
析:9.0
1001.0
1.001*2^3(浮点数表示形式)
0 10000010 00100000000000000000000
1091567616
表示形式:V=(-1)^S*M*2^E
S=0 V为正数 S=1 V为负数
M表示有效数字 1<=M<2
2^E表示指数位(E+12以单精度存入;E+1023以双精度存入)
eg:
5(十进制)
101.0(二进制)
1.01*2^2(浮点表示)-5
-101.0
-1.01*2^2
32位浮点数(单精度浮点数存储模型)
64位浮点数(双精度浮点数存储模型)
static的总结
1,修饰全局变量,改变的是链接属性(外部链接属性——>内部链接属性)
2,修饰局部变量,改变的是存储类型(自动——>静态),同时影响生命周期。
注:不改变作用域。
3,修饰函数,改变链接属性。