已经介绍过了整数和浮点数在内存中的存储方式,接下来我们通过一些具体的代码分析巩固
例1:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
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;
}
输出如下:
分析:
char可以表示的数值范围:-128~127
在当前VS环境下,signed char和char相同,所以a和b的结果相同
unsigned chark可以表示的数值范围:0~255
-1的原码:10000000 00000000 00000000 00000001
-1的反码:11111111 11111111 11111111 11111110
-1的补码:11111111 11111111 11111111 11111111
因为a的类型是char,所以存入数据时,会发生截断,我们操作的序列变为11111111
但是打印数据时以%d的形式打印,所以又会发生整型提升
char 是有符号的,所以整型提升补1
11111111---->11111111 11111111 11111111 11111111 补码
反码:10000000 00000000 00000000 00000000
原码:10000000 00000000 00000000 00000001----> -1
所以最终打印a = -1(a和b一样)
对于c,在整型提升之前与a和b相同
整型提升时,由于c是一个无符号数,所以最高位不代表符号位,提升补0
11111111---->00000000 00000000 00000000 11111111
很明显这是一个正数,原码,反码,补码相同 所以c = 255
例2:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
输出如下:
分析:
我们已经知道char可以表示的数据范围是-128~127
很明显,初始化一个char型的变量为超过其表示范围的数值会发生错误
128的原码/反码/补码:00000000 00000000 00000000 10000000
截断:10000000
整型提升:11111111 11111111 11111111 10000000 补码
以%u,即无符号整型看待这个时,它的最高位不是符号位,是有效数字位,且这个数的原码,反码,补码相同,所以这是一个很大的正数
例3:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
输出如下:
分析:
-20的原码:10000000 00000000 00000000 00010100
-20的反码:11111111 11111111 11111111 11101011
-20的补码:11111111 11111111 11111111 11101100
10的原码/补码:00000000 00000000 00000000 000 01010
补码相加:11111111 11111111 11111111 11101110 补码
反码:10000000 00000000 00000000 00010001
原码:10000000 00000000 00000000 00010010----> -10
例4:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}
输出为打印9,8,7,6,5,4,3,2,1,0后死循环:
分析:
unsigned int类型的数据永远大于0
当i=0时,满足循环条件i>=0,进入循环,打印0
接着i--,此时,i=-1,但是我们知道i是一个无符号整数
-1的补码:11111111 11111111 11111111 11111111
这串二进制序列对于unsigned int来说,最高位不是符号位,而是有效数字位
所以这是一个很大的正数,满足i>=0,所以继续进入循环打印这个正数
例5:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d\n", strlen(a));
return 0;
}
输出如下:
分析:
strlen函数:求字符串中\0之前出现多少字符,\0的ASCII码值是0
char型的数据范围-128~127
a[0]=-1-0=-1
a[1]=-1-1=-2
a[2]=-1-2=-3
... ... ... ...
a[127]=-1-127=-128
a[128]=-1-128=-129 这个数据超出了char的数据范围
-129的原码:10000000 00000000 00000000 10000001
-129的反码:11111111 11111111 11111111 01111110
-129的补码:11111111 11111111 11111111 01111111
要存入char类型的数组,会发生截断:01111111
01111111 -----> 127
所以a[128]=127
a[129]=126
... ... ... ...
a[254]=1
a[255]=0
在0之前,字符的个数是255个,所以strlen(a)的结果是255
实际上,char型的数据在内存中存储的数据可以可视化为下图:
例6:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
输出死循环如下:
分析:
对于一个unsigned char型的是数据来说,它的范围永远是0~255,所以循环的条件i<=255 恒成立,最终导致了死循环
例7:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
if (strlen("abc") - strlen("abcdef") >= 0)
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
输出如下:
分析:
正常情况下,strlen("abc") =3; strlen("abcdef") = 6,结果应该是“<"
strlen库函数
我们可以看到,对strlen库函数,它的返回值是一个size_t类型的数据,其实,size_t就是unsigned char,所以,它的返回值用于是一个无符号数据,俩个无符号数据相加减得到的数据还是一个无符号类型的数据,恒大于零,所以输出为“>”