https://blog.csdn.net/azaz_plus/article/details/129655888?spm=1001.2014.3001.5502
上篇关于数据存储的文章
目录
第一题
// 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;
}
答案:a=-1,b=-1,c=255
解析:
对于此题值得一提的是,char类型其实就是signed char类型,只不过通常我们将signed省略
1.
对于char类型的-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 补码
在上一篇文章中我们提到过,因为这个是char类型的变量,所以我们需要对他进行截断
截断
1111 1111
对于此时截断的值,我们不难发现他的符号位是1,而且是char类型的变量,
所以进行整形提升要补的是1
1111 1111 1111 1111 1111 1111 1111 1111 补码
1111 1111 1111 1111 1111 1111 1111 1110 反码
1000 0000 0000 0000 0000 0000 0000 0001 原码 此时对应的值是-1
通过这个栗子,我们不难发现好像char类型的某些数字在用%d打印的时候并不会发生改变
其实这是一个小小的规律,我们都知道char类型的数据范围是-128~127,
其实,如果char类型的数字没有超过这个值得话,用%d打印是不会改变他的取值的,
这个对于unsigned char类型也同理
(unsigned char类型的范围是0~255)
好的,下面让我们继续来研究一下unsigned char类型的-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 补码
截断
1111 1111
截断之后要进行整形提升,但是值得注意的是,因为此时变量的类型是unsigned 类型的,
是一个无符号数,所以这个时候整形提升要补0,故整形提升之后的值为
0000 0000 0000 0000 0000 0000 1111 1111 补码
而又因为此时的数是一个正数,所以原反补相同,故答案为
0000 0000 0000 0000 0000 0000 1111 1111 即为255
通过对上述题目的讲解我们不难发现
如果给char类型的变量所赋值的数字在char类型之内的话,
那么他的%d打印是不会改变数值的对于另一个 unsigned char 类型的-1打印的时候,
我们发现他的值变成了255,联想一下unsigned char
类型变量的取值范围是0-255不难发现,这其实做了一个周期循环,
也就是说,如果给一个char类型或者
unsigned char类型的变量赋值的时候他的值超过了这个变量的范围之后,
再用%d类型对其进行打印的话,他其实是会做周期性的循环的,
这是一个很容易发现的小规律。
第二题
//2.
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
答案:4294967168
解析:
对于这一道题,值得注意的是%u的意思是打印无符号数
2.
char a = -128;
还是先分析这个数字的原反补
1000 0000 0000 0000 0000 0000 1000 0000 原码
1111 1111 1111 1111 1111 1111 0111 1111 反码
1111 1111 1111 1111 1111 1111 1000 0000 补码
截断
1000 0000
下面要进行的是整形提升,不难发现截断后的数字符号位是1,
并且是char类型的数字,所以整形提升要补1
1111 1111 1111 1111 1111 1111 1000 0000 补码
到了这个地方就要注意了
我们打印的格式是%u类型的,也就是说是无符号打印,所以,上面的补码会被认为是一个无符号数
也就是说上述补码的第一个符号位的1不再代表符号位,而是代表的数值位,并且,此时这个数字会被
认为是正数,也就是说,上面的那个补码就是原码
所以此时对应的值是
1111 1111 1111 1111 1111 1111 1000 0000 4294967168
第三题
//3.
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
答案:4294967168
解析:
这一题与上一题类似
3.
char a = 128;
同样的,我们还是从原反补开始分析
0000 0000 0000 0000 0000 0000 1000 0000 原
值得注意的是,这是一个正数,所以说,原反补相同,不要把这一点给忘了
然后发生截断
1000 0000
截断后我们发现,他的符号位的值是1,而且,又是char类型的数字,所以说要补1
1111 1111 1111 1111 1111 1111 1000 0000 补
跟上面的那个是一样的,因为是用%u类型的打印,所以符号位的1也就被认为是数值位,而且是一个正数
所以,此时对应的值为
1111 1111 1111 1111 1111 1111 1000 0000 4294967168
第四题
//4.
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
答案:-10
解析:
4.
这个怎么说呢,我们可以将上面讲的char类型的小规律扩展到整形
int i= -20;
unsigned int j = 10;
对于这两个变量而言,很明显-20与10都在各自变量的范围之内,所以他们相加的值自然也就是-10了
既然这样,那让我们来看一下另一个代码的输出结果
#include<stdio.h>
int main()
{
int a = -20;
unsigned int b = 10;
int w = a + b;
if (a + b > 0) {
printf("a + b > 0\n");
}
else {
printf("a + b < 0\n");
}
if (w > 0) {
printf("w > 0");
}
else {
printf("w < 0\n");
}
}
这道题的答案是
a + b > 0
w < 0
那这是为什么呢?
首先,上面的第四题输出的值是-10的原因其实是因为%d输出的原因,
这也是 int w 的值小于0的原因。下面的话,
让我们详细的来聊一下关于 unsigned int 与 int 相加大于0的原因
首先,我们需要知道的是,在 unsigned int 类型与 int 类型相加的时候,
会先将 int 类型转化为unsigned int 类型,(这种转换叫隐式转换)
我们等一会再谈关于隐式转换的问题,先来看一下这个题
首先,已知int 类型会转化为unsigned int 类型,而此时int类型的值是
一个负数,所以在其转化为unsigned int类型的时候就会发生一些微妙的变化
int a = -20;
1000 0000 0000 0000 0000 0000 0001 0100 原
1111 1111 1111 1111 1111 1111 1110 1011 反
1111 1111 1111 1111 1111 1111 1110 1100 补
由于此时int会被转化为unsigned int 类型,所以此时它会被认为是一个正数
也就是说此时的符号位变成了数值位,而且会被认为是一个正数
所以此时他对应的数字是一个非常大的数字 4294967276
而这个数字是一个正数他加上10的话还是一个整数,所以说,会输出a + b > 0
好的,下面我们来详细的谈一下什么是 隐式转换
算数运算中,首先有如下类型转换规则:
1、字符必须先转换为整数(C语言规定字符类型数据和整型数据之间可以通用(也就是整形提升)) 。
2、short型转换为int型(同属于整型(也是整形提升)) 。
3、float型数据在运算时一律转换为双精度(double)型,以提高运算精度(同属于实型) 。
其次,有下面的规则。
当不同类型的数据进行操作时,应当首先将其转换成相同的数据类型,然后进行操作,
转换规则是由低级向高级转换。
第五题
//5.
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
答案:无限循环打印i
解析:
5.
Ok,来到第五题,这一题其实非常的简单
一句话就搞定,就是我们前面经常提到的unsigned类型是无符号数,也就是说,
这个类型不存在小于0的数,所以会出现死循环
第六题
//6.
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
答案:255
解析:
6.
如果要解这一道题首先我们需要知道在字符串中'\0'字符是一个结束的标志,
当然,他也可以用0来代替。
然后我们还需要知道strlen这个函数在是统计字符串的长度,它在遇到'\0'的时候终止
(关于这些与字符串相关的函数,以后我会更新一篇相关的博客进行相信的解析)
所以,让我们想一下之前提到的一个小规律,char类型的变量范围是-127~128
而这个是从-1开始的,所以会慢慢的刀-127,然后再减1变成128,最后慢慢变成0
又因为0跟\0是同一个意思,所以说虽然for循环初始化了1000个变量,但是strlen
在读到\0的时候就停止了,故答案是255
第七题
//7.
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
答案:死循环打印hello world
解析:
7.
好的,又见到了我们熟悉的套路,还是要从unsigned char类型的范围出手
因为他的范围是0~255
所以我们永远无法达到大于255的真实,所以,就成了一个无限循环
总结
1.首先,就是开头我们提到的那个简单的小规律,具体怎么用语言表述呢,我这边还没想好,等想好了再过来补充一下
2.然后,就是对于需要整形提升的这一类问题的通用思路
- 原 ----- 反 ----- 补 ----- 截断 ----- 根据变量类型(有符号补符号位,无补零)整形提升 ----- 根据打印类型判断是否需要转回原码(无符号数原反补相同) ----- 得到结果
3.在使用char类型说着unsigned 类型的变量控制循环的时候一定要格外注意他们的取值范围,否则就很容易让代码进入死循环
OK,以上就是本篇文章的全部内容了,感谢您的阅读,如果发现文章的错误或者是需要改进的地方欢迎在我的评论区里留言探讨,最后再次感谢您的阅读,我们下次再见。