C中的有符号到无符号转换 - 它总是安全的吗? [英] Signed to unsigned conversion in C - is it always safe?

查看:35
本文介绍了C中的有符号到无符号转换 - 它总是安全的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下 C 代码.

Suppose I have the following C code.

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

这里发生了哪些隐式转换,这段代码对于 ui 的所有值是否安全?(安全,即使此示例中的 result 会溢出到某个巨大的正数,我也可以将其转换回 int 并获得真正的结果.)

What implicit conversions are going on here, and is this code safe for all values of u and i? (Safe, in the sense that even though result in this example will overflow to some huge positive number, I could cast it back to an int and get the real result.)

推荐答案

简答

您的 i 将通过添加 UINT_MAX + 1转换为无符号整数,然后将使用无符号值进行加法, 导致较大的 result(取决于 ui 的值).

Your i will be converted to an unsigned integer by adding UINT_MAX + 1, then the addition will be carried out with the unsigned values, resulting in a large result (depending on the values of u and i).

长答案

根据 C99 标准:

6.3.1.8 常用算术转换

6.3.1.8 Usual arithmetic conversions

  1. 如果两个操作数的类型相同,则无需进一步转换.
  2. 否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则具有较小整数转换等级的类型的操作数将转换为具有较高等级的操作数的类型.
  3. 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型.
  4. 否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数的所有值,则将无符号整数类型的操作数转换为有符号整数类型的操作数的类型输入.
  5. 否则,两个操作数都转换为与带符号整数类型的操作数类型对应的无符号整数类型.

在您的情况下,我们有一个无符号整数 (u) 和有符号整数 (i).参考上面的 (3),由于两个操作数具有相同的等级,您的 i 需要转换 为无符号整数.

In your case, we have one unsigned int (u) and signed int (i). Referring to (3) above, since both operands have the same rank, your i will need to be converted to an unsigned integer.

6.3.1.3 有符号和无符号整数

6.3.1.3 Signed and unsigned integers

  1. 当整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新的类型表示,则不变.
  2. 否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内.
  3. 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号.

现在我们需要参考上面的(2).您的 i 将通过添加 UINT_MAX + 1 转换为无符号值.因此,结果将取决于您的实现如何定义 UINT_MAX.会很大,但不会溢出,因为:

Now we need to refer to (2) above. Your i will be converted to an unsigned value by adding UINT_MAX + 1. So the result will depend on how UINT_MAX is defined on your implementation. It will be large, but it will not overflow, because:

6.2.5 (9)

涉及无符号操作数的计算永远不会溢出,因为无法由生成的无符号整数类型表示的结果会以比结果类型可表示的最大值大一的数字为模减少.

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

奖金:算术转换半 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;
}

您可以使用此链接在线尝试:https://repl.it/repls/QuickWhimsicalBytes

You can use this link to try this online: https://repl.it/repls/QuickWhimsicalBytes

奖励:算术转换副作用

算术转换规则可以通过将一个无符号值初始化为-1来得到UINT_MAX的值,即:

Arithmetic conversion rules can be used to get the value of UINT_MAX by initializing an unsigned value to -1, ie:

unsigned int umax = -1; // umax set to UINT_MAX

由于上述转换规则,无论系统的带符号数表示如何,都保证可移植.有关更多信息,请参阅此 SO 问题:使用 -1 将所有位设置为 true 是否安全?

This is guaranteed to be portable regardless of the signed number representation of the system because of the conversion rules described above. See this SO question for more information: Is it safe to use -1 to set all bits to true?

这篇关于C中的有符号到无符号转换 - 它总是安全的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆