我尝试将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
两个问题:
-
为什么即使输入在转换过程中被修改,在这些情况下也不会生成警告?
-
在任何一种情况下都需要进行类型转换吗?
4 回答
代码1:此转换定义明确 . 如果
int
超出unsigned int
的范围,则添加UINT_MAX + 1
以使其在范围内 .由于代码是正确和正常的,因此应该没有警告 . 但是你可以尝试使用gcc开关
-Wconversion
,这会产生一些正确转换的警告,特别是有符号无符号转换 .代码2:如果输入大于
INT_MAX
,则此转换是实现定义的 . 很可能,您所使用的实现将其定义为代码1中的转换的反转 .通常,编译器不会警告实现定义的代码,该代码在该实现上定义良好 . 你可以再次使用
-Wconversion
.不需要强制转换,作为一般原则,应该避免强制转换,因为它们可以隐藏错误消息 .
使用
-Wsign-conversion
选项和gcc启用此警告 .签名到无符号转换是由标准很好地定义的,它只是计算模数
UINT_MAX+1
. 所以你永远不会看到警告 .无符号到签名转换是实现定义的,取决于平台 . 您必须查找gcc的文档,以查看是否以及何时将其视为错误 .
并且,不,演员在这里永远不会有帮助 . 它在转换方面的结果总是相同的,你唯一能做到的就是关闭警告,如果有的话 . 事实上,很少有情况下,强制转换在C中有用,而整数到整数转换永远不会出现在这些情况中 .
C89标准的作者指出,大多数当时的编译器在少数特定情况下处理有符号和无符号整数数学,即使计算的数值结果在INT_MAX 1u和UINT_MAX之间 . 这是导致短无符号类型应该提升为“signed int”而不是“unsigned int”的规则的因素之一 . 虽然标准在这种情况下不需要实现来定义行为,但大多数都是这样做的,并且似乎没有理由相信趋势不会继续 .
不幸的是,gcc的作者已经决定,如果结果可能在INT_MAX 1u到UINT_MAX范围内,则需要在执行乘法之前将其中一个操作数强制转换为无符号字符串的代码 . 如果一个人写
而不是
编译器通常会生成适用于UINT_MAX之前的所有结果的代码,但有时会生成在给定此类值时出现故障的代码 .