C语言有符号与符号参数的比较

 1.整型无符号参数与有符号参数比较

代码段:
#include<cstdio>
int main()
{
	int a=-1;
	unsigned int b=0;
	if(b>a)printf("b>a\n");
	else printf("b<a\n");
	printf("a int unsigned:%u\na in int:%d",a,a);
	getchar();
}

运行结果:
    b<a
    a int unsigned: 4294967295
    a in int: -1

原因:计算机中整数以补码的形式存储的【正数的补码等于原码;负数的补码等于反码加1,而反码等于原码符号位不变,其余各位取反】,所以取出来的数为两个补码值比较。(当执行一个运算时(如这里的a>b),如果它的一个运算数是有符号的而另一个数是无符号的,那么C语言会隐式地将有符号 参数强制类型为无符号数,并假设这两个数都是非负的,来执行这个运算,这种说法可能不合理,这里实际就是两个补码值进行比较)。

-1  = 1000 0000 0000 0000 0000 0000 0000 0001  原码

-1 =  1111 1111 1111 1111 1111 1111 1111 1110  反码

-1 =  1111 1111 1111 1111 1111 1111 1111 1111  补码

解决方案:if(b>(int)a)

正数无符号转换成有符号类型没有问题,只是将最高位当做符号位(正数0,负数1)

2.整型无符号与有符号减法

错误代码:
float sum_elements(float a[], unsigned length)  
{  
    int i = 0;  
    float sum = 0;  
    for(i = 0; i <= length -1; ++i)  
    { 
        sum += a[i];  
    }
    return sum;  
} 

如果我告诉你这是一段有错的代码,可能你也不太相信,因为这个函数的一切看起来是这么的自然,因为数据的长度(或个数)肯定是一个非负数,所以把length声明为一个unsigned很合理,计算的数据个数和返回类型也正确。的确如此,但是这都是在length不为0的情况,试想,当调用函数时,把0作为参数传递给length会发生什么事情?回想一下前面我们所说的知识,因为length是unsigned类型,所以所有的运算都被隐式地被强制转换为unsigned类型,所以length-1(即0-1 = -1),-1对应的无符号类型的值为UMax,所以for循环将会循环UMax次,数组也会越界,发生错误。

解决方案:for(i = 0; i < length; ++i)  

3. strlen比较

错误代码:
int strlonger(char *s1, char *s2)  
{  
    return strlen(s1) - strlen(s2) > 0;  
}  

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

解决方案:

从运行结果来看,确实如此,只要s1与s2长度不等,就返回真。那么我们在怎么样改善这段代码呢?其实答案也是很简单的,所函数改为如下即可:

修改之后:
int strlonger(char *s1, char *s2) 
{ 
    return strlen(s1) > strlen(s2); 
} 

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

猜你喜欢

转载自blog.csdn.net/HFHUAZAI/article/details/83893547
今日推荐