为什么我的符号测试总是报告“否定”?

以下程序应打印数组元素的总和是正数还是负数:

#include  #define ARR_SIZE 5 int main() { int array[ARR_SIZE] = {1,-2,3,4,-5}; unsigned sum; int i; for(i=0, sum=0; i -1) printf("non negative\n"); else printf("negative\n"); return 0; } 

该计划没有做到它应该做的事情; 无论收到什么数组值,它都会打印“负数”。

例如,在上面的程序中写入的数组的总和是1,因此我期望以下输出:

 sum 1 sum -1 sum 2 sum 6 sum 1 1 non negative 

而输出是:

 sum 1 sum -1 sum 2 sum 6 sum 1 1 negative 

为什么我得到这个输出?

在表达式sum > -1通常的算术转换 (“平衡”)适用。 由于一个操作数是unsigned int而另一个是int ,因此int的操作数-1被隐式转换为unsigned int 。 比较操作在unsigned int类型上执行。

此外,无符号变量在第一个位置永远不会保持负值,因此即使没有隐式转换,表达式也没有任何意义。

隐式类型转换:当您将变量定义为无符号并将其与负数进行比较时,该负数会隐式地进行类型转换。 正如我们所知,负数存储在两个恭维中,所以-1实际上变成了一个非常大的正数。 现在无论您提供的大数字总是少于那么大的数字,这就是为什么您一直都是负面答案的原因。

可能的解决方案:使用三元运算符来处理+和 – 数字。 谢谢

由于你声明了sum变量的输出,你将它声明为unsigned sum只需将unsigned sum unsigned sum更改为有unsigned sum signed sumint sum

启用一组合理的警告后,一个好的编译器会突出显示问题:

 gcc -std=c11 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds 42362568.c -o 42362568 42362568.c: In function 'main': 42362568.c:19:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if(sum>-1) printf("non negative\n"); ^ 

尽可能多地发出警告总是很好的建议; 由于历史原因,大多数编译器都会发出很少的警告,除非你记得要求它们。

请注意,如果将比较更改为if (sum >= 0) ,那么您将获得不同的(可能更有用)消息,因为文字0可以被视为0u

 42362568.c:19:10: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] if(sum>=0) printf("non negative\n"); ^~ 

当我们尝试比较变量的两个不同(相同数据类型)符号时,编译器隐式(内部)将两个变量视为更高的有符号类型(无符号类型)。

听到if(sum > -1)是你的代码。你正在尝试比较unsigned sum , signed constant因此编译器在内部将-1 as unsigned转换-1 as unsigned 。 如果我们将整数大小视为2个字节,则sum = 1(as your code)-1 will be converted to unsigned value 65535 (do 2's compliment for -1)现在您的代码将简化为if(sum > 65535) ,所以条件是FALSE ,这就是为什么只有你总是得到不期望的结果。如果你想避免这个问题,总是比较相同的签名类型变量(如果两个变量是相同的数据类型,其他明智的是不同的签名类型没有问题也)。

two's compliment of 1 ( assume int size is 2 Bytes )

0000 0000 0000 0001 (1 binary value)

1111 1111 1111 1110 (one's compliment)

1111 1111 1111 1111 (two's compliment) (此值为65535)

在代码中,此值将replacing with -1