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

查看:22
本文介绍了在 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)

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

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天全站免登陆