我尝试将signed int分配给unsigned int。
#include <stdio.h>
int main()
{
int a;
unsigned int b;
scanf("%d", &a);
b = a;
printf("%d %u\n", a, b);
return 0;
}
我希望编译这个会引起我的警告 将int值赋给unsigned int变量。但我没有得到任何 警告。
$ gcc -std=c99 -Wall -Wextra -pedantic foo.c
$ echo -1 | ./a.out
-1 4294967295
接下来,我尝试将unsigned int分配给signed int。
#include <stdio.h>
int main()
{
int a;
unsigned int b;
scanf("%u", &b);
a = b;
printf("%d %u\n", a, b);
return 0;
}
仍然没有警告。
$ gcc -std=c99 -Wall -Wextra -pedantic bar.c
$ echo 4294967295 | ./a.out
-1 4294967295
两个问题:
答案 0 :(得分:5)
代码1:此转换定义明确。如果echo "nmcli tool, version 1.1.93" |sed "s/[^0-9]//g" |cut -c1
1
echo "nmcli tool, version 1.1.93" |grep -o '[0-9]' |head -1
1
超出int
范围,则会添加unsigned int
以使其在范围内。
由于代码正确且正常,因此应该没有警告。但是,您可以尝试使用gcc开关UINT_MAX + 1
,它会对某些正确的转换产生警告,尤其是有符号无符号转换。
代码2:如果输入大于-Wconversion
,则此转换是实现定义的。很可能,您所使用的实现将其定义为代码1中转换的反转。
通常,编译器不会警告实现定义的代码,该代码在该实现上定义良好。您可以再次使用INT_MAX
。
不需要强制转换,作为一般原则,应该避免使用强制转换,因为它们可以隐藏错误消息。
答案 1 :(得分:4)
使用gcc
的-Wsign-conversion
选项启用此警告。
-Wsign-conversion
警告可能会更改整数值符号的隐式转换,例如将有符号整数表达式赋值给无符号整数变量。显式演员使警告无声。在C中,此选项也由-Wconversion启用。
答案 2 :(得分:4)
签名到无符号转换是由标准定义的,它只是计算模UINT_MAX+1
。所以你永远不会看到警告。
无符号到签名转换是实现定义的,与平台有关。您必须查找gcc的文档,看看是否以及何时将其视为错误。
而且,不,演员在这里永远不会有帮助。它在转换方面的结果总是相同的,你唯一能做到的就是关闭警告,如果有的话。事实上,很少有情况下强制转换在C中有用,而整数到整数转换永远不会出现在这些情况中。
答案 3 :(得分:0)
C89标准的作者指出,大多数当时的编译器在少数特定情况下处理有符号和无符号整数数学,即使计算的数值结果在INT_MAX + 1u和UINT_MAX之间。这是导致短无符号类型应该提升为“signed int”而不是“unsigned int”的规则的因素之一。虽然标准在这种情况下并不要求实施来定义行为,但大多数都是这样做的,似乎没有理由相信这种趋势不会继续下去。
不幸的是,gcc的作者已经决定,如果结果可能在INT_MAX +范围内,则需要在执行乘法之前将其中一个操作数强制转换为无符号字符串的代码。 1u到UINT_MAX。如果写一个
unsigned multiply(int x, unsigned char y) { return x*y; }
而不是
unsigned multiply(int x, unsigned char y) { return (unsigned)x*y; }
编译器通常会生成适用于所有结果的代码 到UINT_MAX,但有时会生成在给定时出现故障的代码 这样的价值观。