假设我有以下C代码.
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
这里正在进行什么隐式转换,这段代码对所有值u
和i
都安全吗?(安全,从这个意义上说,即使本例中的result将溢出到某个巨大的正数,我也可以将其转换回int并获得真正的结果.)
假设我有以下C代码.
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
这里正在进行什么隐式转换,这段代码对所有值u
和i
都安全吗?(安全,从这个意义上说,即使本例中的result将溢出到某个巨大的正数,我也可以将其转换回int并获得真正的结果.)
Short Answer个
通过加UINT_MAX + 1
,你的i
将是converted到一个无符号整数,然后用无符号值进行加法,得到一个大的result
(取决于u
和i
的值).
Long Answer
根据C99标准:
6.3.1.8常用算术转换
- 如果两个操作数的类型相同,则无需进一步转换.
- 否则,如果两个操作数都具有带符号整数类型或都具有无符号整数类型,则将具有较小整数转换秩的类型的操作数转换为具有较大秩的操作数的类型.
- 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型.
- 否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则无符号整数类型的操作数将转换为有符号整数类型的操作数的类型.
- 否则,两个操作数都将转换为与带符号整数类型的操作数类型对应的无符号整数类型.
在你的例子中,我们有一个无符号整数(u
)和有符号整数(i
).参考上面的(3),由于两个操作数的秩相同,i
必须是converted到无符号整数.
6.3.1.3有符号和无符号整数
- 当整数类型的值转换为除_Bool以外的其他整数类型时,如果该值可以用新类型表示,则该值不变.
- 否则,如果新类型是无符号的,则会通过反复将新类型中可以表示的最大值加上或减go 一个来转换该值,直到该值在新类型的范围内.
- 否则,新类型将被签名,并且无法在其中表示值;要么结果是实现定义的,要么发出实现定义的信号.
现在我们需要参考上面的(2).您的i
将通过添加UINT_MAX + 1
转换为无符号值.因此,结果将取决于如何在实现中定义UINT_MAX
.它会很大,但不会溢出,因为:
6.2.5 (9)
涉及无符号操作数的计算永远不会溢出,因为不能由结果无符号整数类型表示的结果将被减少为比结果类型可以表示的最大值大一的数的模.
Bonus: Arithmetic Conversion Semi-WTF个
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
你可以使用此链接在线try :https://repl.it/repls/QuickWhimsicalBytes
Bonus: Arithmetic Conversion Side Effect
算术转换规则可用于通过将无符号值初始化为-1
来获得UINT_MAX
的值,即:
unsigned int umax = -1; // umax set to UINT_MAX
由于上面描述的转换规则,无论系统的符号数字表示形式如何,这都保证是可移植的.更多信息请参见此问题:Is it safe to use -1 to set all bits to true?