一些关于无符号类型的有趣代码与思考

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以及unsigned char说起。

我们知道int类型占4个字节,而char占1个字节,要把一个整数用char类型存储,便会发生截取,只会截取补码最低位的那个字节即八个比特位。

原码: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

在当前环境下,char与signed char是等价的,对于unsigned char来讲,此时与char在内存中存储的内容是一样的,故有:

三者此时在内存中存放的八个比特位均为 11111111

我们又可以看见此时将三个数都以%d的形式输出,char类型仅有一个字节,%d整型形式输出需要4个字节,故此时便需要整型提升

整型提升:

原符号位进行提升,char a = -1,此时char与signed char等价,故其符号位为1,前面的24个比特位全补为1即可,故有:

11111111 11111111 11111111 11111111

此为补码,将其减一再取反后得原码:

10000000 00000000 00000000 00000001

十进制即为-1,char与signed char等价,故二者均输出-1。

对于unsigned char来说,其为无符号型,整型提升之前的24个比特位全补0,故有:

00000000 00000000 00000000 11111111

unsigned 类型原码、反码与补码相等,故其原码也为:

00000000 00000000 00000000 11111111

十进制即为255。

2.现有以下代码

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

运行结果为:

 

结果似乎又很出人意料,但其实依然有迹可循。

首先我们要知道当以%u打印时,原码、反码,补码是相同的。

对于-128来说,它的原码为: 10000000 00000000 00000000 10000000

补码:

11111111 11111111 11111111 10000000

因其为char类型存储,故要截取低位字节,此时有补码:

1000 0000

再进行整型提升有:

11111111 11111111 11111111 10000000

因为最后以%u,无符号整型输出,故以十进制输出有:

 

这与开始运行结果相一致。

此外有类似的一段代码:

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

答案自然呼之欲出,正数原反补码相同,截取低位字节再进行整型提升以无符号整型输出后与以上结果自然保持一致。

3.有代码如下:

int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j);

运行结果为:

 

结果也很好理解。

-20的原码二进制序列为:

10000000 00000000 00000000 00010100

补码为:

11111111 11111111 11111111 11101100

unsigned int j = 10 ;此时j的补码二进制序列为:

00000000 00000000 00000000 00001010

相加易得补码为:

11111111 11111111 11111111 11110110

则原码为:

10000000 00000000 00000000 00001010

十进制即为-10。

4.有代码如下:

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

运行结果为一死循环,是什么原因呢?

首先我们知道,unsigned int的值始终大于等于0,故其一定为一死循环,但是循环的值是多少呢?

i=9时进入循环,此时原码反码补码相等,以%u输出亦为9,故在for循环中依次输出9、8、7、6、5、4、3、2、1、0

当0输出过后,i此时变为-1,-1的补码二进制序列为:

11111111 11111111 11111111 11111111

%u将以无符号类型直接输出,故会输出:

‭4294967295‬

紧接着会以同样的方式输出-2,-2的补码二进制序列为:

11111111 11111111 11111111 11111110

故会输出:

‭4294967294

当然我们也可以在编译器中清晰的看见这一点。

 

5. 有代码如下:

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

首先我们应该明确strlen() 函数计算的是字符串的实际长度,遇到第一个'\0'结束,而此时的0即为'\0'

看见一上来先定义了一个char类型的数组,我们思考一下,一个char类型的变量中能存放什么数值呢?

1byte=8bit

对于unsigned char来说,其取值范围有

0000 0000至1111 1111

即0至255

对于signed char来说,其取值范围可抽象为一个

 

故其取值范围为-128至127

推而广之我们也可以用同样的方法来计算出signed short的取值范围为-32768至32767

那么这段代码就很容易就可以判断出结果:

a[i]==-1;

a[i]==-2;

...

a[i]==-128;

a[i]==127;

...

a[i]==1;

a[i]==0; 此时strlen函数已经返回值了,返回值为128+127=255

 

6. 现有一段代码:

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

首先看见i被定义为无符号char类型,故其永远不可能小于零,因此首先可以判断出该循环一定为一死循环。

由上题易知unsigned char的取值范围为0-255,因此该循环将无限执行。

我们可以很明显的感觉到,数据类型不管如何变化总是有规律可循的,每一种数据都有自己严格的标准,这种严谨的框架有一种别样的魅力。

此外无符号类型总给人一种难以限制的感觉,因此要慎用无符号类型作为循环限制条件,以免出现未知的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值