C语言不踩坑:有符号数与无符号数相比较

与本文有关的可以结合这篇文章一起看:C语言不踩坑: 自动类型转换规则 ,这篇文章讲的是在一个运算式中出现不同类型数据的情况

1.首先看一个例程:

#include <stdio.h>
 
int main(void)
{
	int a = -1;
	unsigned int b = 1;
	if (a > b) {
		printf("a > b\n");
	} else {
		printf("a <= b\n");
	}
	
	return 0;
}

VS运行结果:
在这里插入图片描述
VS在编译时还给出了警告:
在这里插入图片描述
很明显 -1>1 的结果令人意外,这是因为C语言在两个不同类型变量进行比较时,进行了自动类型转换,这里的int类型的a在与unsigned int的b比较时,a自动转变成了unsigned int,也就是4294967295,所以实际是4294967295与1在比较,结果自然是4294967295大于1。

2.再来看一种现实在写程序时更容易遇到的情况

sum_elements是一个求数组中前length个数据的和的函数,数组中元素的个数由参数length给出

int sum_elements(int a[], unsigned int length)
{
    int i;
    int result = 0;
    for (i = 0; i <= length - 1; i++) 
        result += a[i];
    return result;
}

如果我告诉你这是一段有错的代码,可能你也不太相信,因为这个函数的一切看起来是这么的自然,因为数据的长度(或个数)肯定是一个非负数,所以把length声明为一个unsigned int很合理,计算的数据个数和返回类型也正确。的确如此,但是这都是在length不为0的情况,试想,当调用函数时,把0作为参数传递给length会发生什么事情?

int main(void)
{
    int a[] = {1, 2, 3};
    int m = sum_elements(a, 0); // 故意传 0
    printf("%d\n", m);
    return 0;
}

回想一下前面我们所说的知识,因为length是unsigned类型,所以所有的运算都被隐式地被强制转换为unsigned类型,所以length-1(即0-1 = -1),-1对应的无符号类型的值为UMax,所以for循环将会循环UMax次,数组也会越界,发生错误。

如果想改进上面的程序:

for(i = 0; i < length; ++i)  

这样当length为0也不会有问题。

3.判断第一个字符串是否长于第二个字符串,若是,返回1,若否返回0,代码如下:

int strlonger(char *s1, char *s2)
{  
    return strlen(s1) - strlen(s2) > 0;  
}  

注意这里有一个数据类型size_t,它被定义在stdio.h文件中,其实它就是unsigned int,一个字符串的长度当然不可能为负,这样的定义显然是合理的,但是有时却因为这样,而存在不少的问题,如函数strlonger的实现。当s1的长度大于等于s2时,这个函数并没有什么问题,但是你可以想像,当s1的长度小于s2的长度时,这个函数会返回什么吗?没错,因为此时strlen(s1) - strlen(s2)为负(从数学的角度来解释的话),而又由于程序把它作为unsigned为处理,则此时的值肯定是一个比0大的值。换句话来说,这个函数只有在strlen(s1) == strlen(s2)时返回假,其他情况都返回真。

如果想改进上面的程序:

int strlonger(char *s1, char *s2)  
{  
    return strlen(s1) > strlen(s2);  
} 

这样就可以利用两个无符号数进行直接的比较,而不会因为减法而出现负数而影响比较结果。

总结:

1.不要把有符号和无符号数进行比较
2.当比较符号的一边有减法运算式时注意有无可能运算结果为负数
3.注意无符号的使用,因为在unsigned的世界里,x-y>0与x>y是不等价的

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吾爱技术圈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值