char类型存储结构的详细讲解(第三期)

本文详细探讨了C语言中char类型的有符号与无符号特性,包括取值范围、整形提升的概念与规则,并通过实例解析了相关运算和函数应用,如strlen()。同时,分析了涉及char类型的循环和溢出问题,揭示了可能导致死循环的原因。

目录

 

1.比特七道练习题

   1.第一题

       1.1 整形提升的概念

       1.2 整形提升的规则

       1.3 char的初定义

   2.第二题

       2.1 剖析有符号char类型的取值范围

       2.2 无符号char类型的取值范围

  3.第三题

       3.1 char类型取值范围的应用

  4.第四题

       4.1 有符号整形与无符号整形的计算

  5.第五题

      5.1  循环恒成立时,死循环

  6.第六题

      6.1  浅析strlen函数

  7.第七题

      7.1  无符号char类型取值范围的应用

      7.1 无符号char类型取值范围应用


1.比特七道练习题

1.第一题

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类型a,当a = -1的时候,因为char类型占一个字节(8个比特位)即内存条应该为

 如图所示,计算机先把char类型的a变量以11111111形式存储在计算机中,但是在练习题中需要把a用%d的形式打印出来,这里就需要一个概念叫“整形提升”。

那么什么是整形提升?


1.1 整型提升的概念

       整形提升是隐式转换的一种特殊情况。
       首先说明计算机进行逻辑和算术运算是在CPU相应运算器件内执行的。而数据是保存在内存里的,CPU进行运算时要将数据从内存保存到CPU的寄存器里。而CPU通用寄存的长度是与int(整形)字节长度相同,也就是4字节长度。
       所以当表达式中各种长度小于int长度的整形值做逻辑或者算术运算时,都必须先转为int或者unsigned int,然后再进行运算。

1.2 整形提升的规则

整型提升分为有符号和无符号两种:

       1.有符号的整型提升时是按照变量的补码被截断时的最高位是什么进行补位的,如果截断后最高位即最左面的一位数为 1 则在最高位前补 1 ,如果最高位是 0 则在前面补 0 ,补够32位即int类型即可。

       2.无符号的: 直接在被截断的前面补 0 即可。


那么我们回到第一个题目,我们已经知道了char类型a变量的补码存储,现在a变量需要进行整形提升以int类型打印。

 这里我们由图可以得到,char类型a变量通过整形提升为int类型后原码的值为 - 1。


 这里char  a 与 signed  char  b为什么得到的是一样的值呢,这里也需要穿插一个对于char类型的初定义知识点。

1.3  char的初定义

C标准中对char是 Impementation Defined,就是未明确定义

(1)那它由什么定义?坦白说,具体的编译器明确定义,一般都是用signed char或unsigned char来实现char的,也就是说不同的编译器对char是什么定义不一样

(2)为什么要这样定义?因为这三种类型的对象在存储介质中的表现形式是一样的(都是一个占8bit的01串,只是解析的时候不同)

(3)到底是signed char还是unsigned char?这得看编译器:VC编译器、x86上的GCC都把char定义为signed char,而arm-linux-gcc却把char定义为 unsigned char

所以对于vc编译器中,对于char类型的初始定义是signed  char (有符号类型字符类型),即char与signed  char是等价的,所以b与a所得到的结果是一样的。


 下面我们在分析无符号字符c变量的内存存储:

C变量在存储中是一样的都是以   1 1 1 1 1 1 1 1的形式进行存储在计算机中。不同之处在于在发生整型提升中是以无符号类型规则进行提升。

 

 由图可知,C变量整形提升后是00000000 00000000 00000000 11111111,以十进制形式打印得  c = 255。


2.第二题

2.
#include <stdio.h>
int main()
{
    char a = -128;
    printf("%u\n",a);
    return 0;
}

上面这段代码输出什么呢?

a = 4294967168


下面我们需要剖析下char类型的取值范围:

2.1 剖析有符号的char类型取值范围

 我们以内存条的形式展示可以看见正数的范围为0~129,负数的范围为-0到-1。这里就会发现不同点-0的下一位是-127然后到-1。这里我们在计算一下-128的存储值是多少,惊奇的发现-128的截断后的补码与-0的补码是一样的。所以在char类型中我们把-0就等同于-128。所以有符号char类型的取值范围就是-128 ~ 127。

 下面我们来了解一下,char类型的取值范围是-128~127那么+128会得到怎么样的结果呢?

假如我们输入 -129又会得到怎么样的结果呢?

 通过以上的实验我们可以得到

char a = 128 超出了127的范围实际上等于-128

char a = -129 超过了-128的范围实际上等于127

下面我们来解剖下为什么会得到这二个结果:

所以我们可以把有符号char类型看成一个圆形的取值范围:

 


2.2 无符号char类型的取值范围

无符号char类型就是没有符号位,取值范围就是0000 0000 ~ 1111 1111(0 ~ 255)。

下面我们再回到那个题目进行分析:

char a = -128

在上面的范围剖析中我们得到-128在int类型下的

补码:11111111 11111111 11111111 10000000

因为要以无符号整形的形式进行打印,所以没有符号位,符号位作为位数考虑

a = 4294967168


3.第三题 

3.
#include <stdio.h>
int main()
{
    char a = 128;
    printf("%u\n",a);
    return 0;
}

输出:

a = 4294967168

3.1 char类型取值范围的应用 

这题的结果和上面的一样,我们用上面讲到的知识分析一下:

在上面我们已经验证到+128就等于-128;也就是char a = 128等同于char a = -128;

而第二题就是求的char a = -128以%u的形式打印出来。


4.第四题

4.
int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j); 
//按照补码的形式进行运算,最后格式化成为有符号整数

 输出的结果:

i + j = -10

那么为什么得到这个结果呢,我们要剖析下:

4.1 有符号整形与无符号整形的计算

 无论是无符号整形还是无符号整形我们都先把他的补码算出来,核心上就是用补码进行加减计算。

当我们算出-20的补码与10的补码后直接进行补码的运算就行了,但是需要注意的是补码加减补码最后得到的结果还是补码,我们要以%d的形式进行打印,所以我们需要求出原码,最后得到的结果为 - 10。

5.第五题

5.
unsigned int i;
for(i = 9; i >= 0; i--)
{
    printf("%u\n",i);
}

 输出结果:死循环

5.1 循环恒成立时,死循环

为什么会陷入死循环呢,我们来剖析分析一下: 

 这里需要注意的那就是,无符号整形数据是没有负数的,这里for循环正好就是,i >= 0,但是无符号数本来就是恒大于等于0的数字,所以当i = 0的时候,再进行i--的时候就会得到超级大的数据。

 所以得到超级大的数据之后又是大于0的数,就会再次进入循环,直到减到0,这时候又会得到超级大的数据,然后陷入死循环。

6.第六题

6.
int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
   {
        a[i] = -1-i;
   }
    printf("%d",strlen(a));
    return 0;
}

输出:

strlen(a) = 255

 6.1 浅析strlen函数

为什么会得到255这样一个结果呢?下面我们来剖析一下这个题

我们先计算一下这个char类型的数组里面放了1000个什么样的数据:

当i = 0时     a[0] = -1;

当i = 1时     a[1] = -2;

当i = 2时     a[2] = -3;

                ~

当i = 127时   a[127] = -128;

当i = 128时   a[128] = 127;

  (在前面我们的圆形范围中,我们可以得到char类型中没有-129,当超过-128后会转到127这个数据)

当 i = 129时  a[129] = 126;

              ~

当 i = n 时     a[n] = 0;

当 i = n+1时  a[n+1] = -1;

后面就会一直进行循环,我就不一一列举了。

 我们知道strlen函数是计算字符串的长度,但是这里是strlen(a),计算char 数组类型的长度是怎么样进行计算呢?

 这里我们需要了解的是,strlen的原理是计算'/0'之前的长度。所以我们只需要寻找 0 之前的长度就行了(' \0 '就等价于' 0 ')

这样我们就找到了在第一个0之前的数据是:

-1 -2 -3 -4 ~  -128  127 126 ~ 1 0      (128 + 127 = 255)

所以strlen(a)= 255。

7.第七题 

#include <stdio.h>
unsigned char i = 0;
int main()
{
    for(i = 0;i<=255;i++)
   {
        printf("hello world\n");
   }
    return 0;
}

输出:

死循环 

 7.1 无符号char类型取值范围应用

为什么会得到死循环的结果呢,应该是循环266次打印266次“hello world”。

 因为char类型之占一个字节(8个比特位)在放入内存存储中的时候会进行截断处理,当0~255依次就行i++命令后,在256时截断后的8位就是:00000000这时候就回到了0这个数据后又进行同样的循环,所以最后的结果是死循环了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C-Sakura

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值