目录
数据类型的意义
大小端介绍
例题1:设计一个小程序输出存储方式:
例题2:下列程序输出什么,为什么
例题3:下列程序输出什么,为什么
例题4:下列程序输出什么,为什么
例题6:下列程序输出什么,为什么
例题7:下列程序输出什么,为什么
例题8:下列程序输出什么,为什么
浮点型在内存中的存储
类型的意义
1、使用这个类型开辟内每空间的大小(大小决定了使用范围)。
2、如何看待内存空间的视角。
案例:看a在内存是怎么存放的
int main()
{int a = -10;//原码:10000000 00000000 00000000 00001010//反码:11111111 11111111 11111111 11110101//补码:11111111 11111111 11111111 11110110//换成16进制:FF FF FF F6return 0;
}
//数据在内存中以2进制的形式存储
//对整数来说:
//整数二进制有3种表示形式:原码、反码、补码
//正整数:原码、反码、补码相同
//负整数:原码、反码、补码进行计算
//按照数据的数值直接写出的二进制序列就是原码
//原码的符号位不变,其他位按位取反,得到的就是反码
//反码+1,得到的就是补码
//内存存储的是补码
F10调试,查看内存的信息:
什么大端小端:
- 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
- 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
为什么有大端和小端:
- 这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
- 例如一个16bit的short型x,在内存中的地址为0x0010,的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的x86 结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
int main()
{int a = 1;char* p = (char*)&a;if(*p == 1){printf("小端存储\n");}elseprintf("大端存储\n");return 0;
}
或者写一个函数输出存储方式:
int check_sys()
{int i = 1;char* p = (char*)&i;return *p;
}
int main()
{int ret = check_sys();if(ret == 1){printf("小端存储\n");}elseprintf("大端存储\n");return 0;
}
int main()
{char a =-1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d",a,b,c);return 0;
}
原因为下列:
int main()
{char a =-1;//补码位:11111111 11111111 111111111 11111111//因为为char,所以为:11111111//因为默认为signed,高位第一个1为符号位,又因为要输出%d,所以要整形提升//整形提升为:11111111 11111111 111111111 11111111(有符号的补符号位)//所有原码为:-1signed char b = -1;//和char一样的,上面的额char是省略了signedunsigned char c = -1;//补码位:11111111 11111111 111111111 11111111//因为为char,所以为:11111111//因为为unsiged,所有整形提升前面补0//整形提升为:00000000 00000000 000000000 11111111//所以原码为:255printf("a=%d,b=%d,c=%d",a,b,c);return 0;
}
int main()
{char a =-128;printf("%u\n",a);return 0;
}
因为:
int main()
{char a =-128;//原码:10000000 00000000 00000000 10000000//反码:11111111 11111111 11111111 01111111//补码:11111111 11111111 11111111 10000000//因为char,所以只能存放8个bit位:10000000//因为是以%u(无符号整形)的方式打印的,需要整形提升//又因为整形提升是用之前的char提升的为:11111111 11111111 11111111 10000000//所以原码为:11111111 11111111 11111111 10000000为:4294967168printf("%u\n",a);return 0;
}
int main()
{char a = 128;printf("%u\n",a);return 0;
}
因为:
int main()
{char a = 128;//原码:00000000 00000000 00000000 10000000//因为char,所以只能存放8个bit位:10000000//因为是以%u(无符号整形)的方式打印的,需要整形提升//又因为整形提升是用之前的char提升的为:11111111 11111111 11111111 10000000//所以原码为:11111111 11111111 11111111 10000000为:4294967168printf("%u\n",a);return 0;
}
//char类型的取值范围:-128到127
例题5:下列程序输出什么,为什么
int main()
{int i = -20;unsigned int j = 10;printf("%d\n",i + j);return 0;
}
int main()
{int i = -20;//原码:10000000 00000000 00000000 00010100//反码:11111111 11111111 11111111 11101011//补码:11111111 11111111 11111111 11101100unsigned int j = 10;//原反补码:00000000 00000000 00000000 00001010printf("%d\n",i + j);//i补码: 11111111 11111111 11111111 11101100//j补码: 00000000 00000000 00000000 00001010//相加得:11111111 11111111 11111111 11110110//因为要%d,所以要以有符号位打印 //得反码:11111111 11111111 11111111 11110101//得原码:10000000 00000000 00000000 00001010 -> -10return 0;
}
int main()
{unsigned int i;for (i = 9; i>= 0;i--){printf("&u\n",i);}return 0;
}
//死循环
#include
int main()
{char a[1000];int i;for (i =0;i<1000;i++){a[i] = -1-i;}
printf("%d\n", strlen(a));
return 0;
}
#include
int main()
{char a[1000];int i;for (i =0;i<1000;i++){a[i] = -1-i;}//-1 -2 -3 ... -127 -128 127 126 123 ...3 2 1 0 -1 -2 ...//128+127=255//所以输出255
printf("%d\n", strlen(a));
return 0;
}
unsigned char i = 0;
int main()
{for(i = 0;i <= 255; i++){printf("hello world\n");}return 0;
}
//输出死循环
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式:
- (-1)^S*M*2^E
- (-1)^S表示符号位,当s=0,V为正数;当=1,V为负数。
- M表示有效数字,大于等于1,小于2。
- 2^E表示指数位
举例:
- 十进制的 5.0 ,写成二进制是 101.0 ,相当于 1.01×2^2 。
- 那么,按照上面 V 的格式,可以得出 s=0 , M=1.01 , E=2 。
- 十进制的 -5.0 ,写成二进制是 - 101.0 ,相当于 - 1.01×2^2 。
- 那么, s=1 , M=1.01 , E=2 。
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M
下面例子:
int main()
{float f = 5.5f;//101.1//1.011 * 2^2//s=0 M=1.011 E=2//s=0 M=011 E=2+127//0100 0000 1011 0000 0000 0000 0000 0000//40 b0 00 00return 0;
}
- IEEE 754 对有效数字 M 和指数 E ,还有一些特别规定。
- 前面说过, 1≤M
- IEEE 754 规定,在计算机内部保存 M 时,默认这个数的第一位总是 1 ,因此可以被舍去,只保存后面的xxxxxx部分。比如保存 1.01 的时候,只保存01 ,等到读取的时候,再把第一位的 1 加上去。这样做的目的,是节省 1 位有效数字。以 32 位浮点数为例,留给M 只有 23 位,将第一位的1 舍去以后,等于可以保存 24 位有效数字。
- 因为M都是1.XXX的形式,所以只存XXXX的形式,这样M就可以多存1位有效数字,能过提高精准度
- 至于指数 E ,情况就比较复杂。
- 首先, E 为一个无符号整数( unsigned int )
- 这意味着,如果 E 为 8 位,它的取值范围为 0~255 ;如果 E 为 11 位,它的取值范围为 0~2047 。但是,我们知道,科学计数法中的E 是可以出 现负数的,所以 IEEE 754 规定,存入内存时 E 的真实值必须再加上一个中间数,对于 8 位的 E,这个中间数是127 ;对于 11 位的 E ,这个中间 数是1023 。比如, 2^10 的 E 是 10 ,所以保存成 32 位浮点数时,必须保存成 10+127=137,即 10001001 。
解释下下面代码输出什么
int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);*pFloat = 9.0;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);return 0;
}
输出:
n的值为:9
*pFloat的值为:0.000000
n的值为:1091567616
*pFloat的值为:9.000000
请按任意键继续. .
int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);//9的二进制:00000000 00000000 00000000 00001001//上面二进制第一位:S,第二位到第9位:E,余下位:M//E全0所以打印出来就是0.0000000*pFloat = 9.0;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);//9.0:1001.0//1.001*2^3//E=3// 0 10000010 001000000000000000//0100 0001 0001 0000 0000 0000 0000 0000//81 10 00 00//
下一篇:密码学基本概念