为什么整型提升的结果有什么不同? [英] Why are the results of integer promotion different?

查看:208
本文介绍了为什么整型提升的结果有什么不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请看看我的测试code:

 的#include<&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#定义PRINT_COMPARE_RESULT(A,B)\\
    如果(A> B){\\
        的printf(#A>中#B\\ n); \\
    } \\
    否则,如果(A< B){\\
        的printf(#A<#B\\ n); \\
    } \\
    其他{\\
        的printf(#A=#B\\ n); \\
    }诠释的main()
{
    签署int类型的= -1;
    unsigned int类型B = 2;
    签署的短小c = -1;
    无符号短D = 2;    PRINT_COMPARE_RESULT(A,B);
    PRINT_COMPARE_RESULT(C,D);    返回0;
}

结果如下:

  A> b
C< ð

我的平台是Linux和我的gcc版本是4.4.2。
我对输出的第二行感到惊讶。
输出的第一行是由整数提升引起的。但是,为什么是第二行的结果不同?

以下规则从C99标准:


  

如果两个操作数具有相同的类型,则不需要进一步的转换。
  否则,如果两个操作数有符号整数类型或都有签名
  整数类型,具有较小的整数转换等级类型的操作数
  转换为操作数的类型以更大的等级


  
  

否则,如果具有无符号整型操作数的秩大于或
  等于其它操作数的类型的秩,则与操作数
  有符号整数类型转换为无符号的操作数的类型
  整数类型。


  
  

否则,如果与符号整型操作数的类型可以重新present
  所有与无符号整型操作数的类型的值,则
  与无符号整型的操作数转换为的类型
  操作有符号整数类型。


  
  

否则,两个操作数被转换为无符号整型
  对应于与符号整型操作数的类型


我觉得无论是两个比较的应该属于同一案件中,整数推广的第二种情况。


解决方案

当您使用的算术运算符,操作数经过两次转换。

整数优惠:如果 INT 可以重新present所有类型的值,那么操作数提升为int。这适用于无符号短在大多数平台上。在此阶段执行的转换是对每个操作数分别,而无需其他操作方面。 (有更多的规则,但是这是一个适用的人。)

通常的算术转换:如果您比较一个 unsigned int类型针对符号int ,因为无论包括其他的整个范围,并且具有相同的等级,那么这两个被转换为无符号键入。这种转换是检查两个操作数的类型后进行。

显然,通常的算术转换并不总是适用,如果没有两个操作数。这就是为什么有两套规则。有一个问题,例如,是移位运算符<< >> 不做平常算术转换,因为结果的类型应该只依赖于左操作数(所以如果你看到有人键入 X<< 5U ,那么 U 表示没有必要)。

故障:让我们假设有32位int和16位典型的系统短

  int类型的= -1; //签名被暗示
符号B = 2; //INT是隐含的
如果(A< B)
    看跌期权(A< B); //不打印
其他
    看跌期权(一> = B); //打印


  1. 首先,两个操作数被提升。因为两者都是 INT unsigned int类型,不促销就完成了。

  2. 接着,将两个操作数被转换为相同的类型。由于 INT 不能重新present的无符号符号所有可能的值不能重新present INT 的所有可能值,没有明显的选择。在这种情况下,无论是被转换为无符号

  3. 当从符号到无符号转换,2 32 重复添加到符号的值,直到它的无符号值的范围。这实际上是一个空操作,只要处理器的关注。

  4. 因此比较变得如果(4294967295U< 2U),这是假的

现在,让我们尝试将其与

 的短小c = -1; //签名被暗示
无符号短D = 2;
如果(C< D​​)
    看跌期权(C< D​​); //打印
其他
    卖出期权(c取代; = D); //不打印


  1. 首先,两个操作数被提升。由于既可以通过重新 INT 忠实psented $ P $,两者都提升到 INT

  2. 接着,它们被转换为相同的类型。但是他们已经是同一类型, INT ,所以什么都不做。

  3. 因此比较变得如果(-1 2)。,这是真的

编写好的code:有赶在code,这些陷阱的简单方法。只是总是打开的警告编译,并修复警告。我倾向于写code是这样的:

  INT X = ...;
无符号Y = ...;
如果(X℃,||(无符号)X - 下; y)的
    ...;

您必须注意,任何code你写不碰到其他签名与未签名的疑难杂症:符号溢出。例如,下面的code:

  INT X = ...,Y = ...;
如果(X + 100℃; Y + 100)
    ...;
无符号的一个= ...,B = ...;
如果(A + 100℃; B + 100)
    ...;

一些流行的编译器将优化(X + 100℃; Y + 100)(X< Y),但这是另一天的故事。只是不溢出的符号数。


  

脚注:请注意,虽然签署是隐含的 INT 长长,这是不是暗示了字符。相反,它取决于平台。


Please look at my test code:

#include <stdlib.h>
#include <stdio.h>


#define PRINT_COMPARE_RESULT(a, b) \
    if (a > b) { \
        printf( #a " > " #b "\n"); \
    } \
    else if (a < b) { \
        printf( #a " < " #b "\n"); \
    } \
    else { \
        printf( #a " = " #b "\n" ); \
    }

int main()
{
    signed   int a = -1;
    unsigned int b = 2;
    signed   short c = -1;
    unsigned short d = 2;

    PRINT_COMPARE_RESULT(a,b);
    PRINT_COMPARE_RESULT(c,d);

    return 0;
}

The result is the following:

a > b
c < d

My platform is Linux, and my gcc version is 4.4.2. I am surprised by the second line of output. The first line of output is caused by integer promotion. But why is the result of the second line different?

The following rules are from C99 standard:

If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

I think both of the two comparisons should belong to the same case, the second case of integer promotion.

解决方案

When you use an arithmetic operator, the operands go through two conversions.

Integer promotions: If int can represent all values of the type, then the operand is promoted to int. This applies to both short and unsigned short on most platforms. The conversion performed on this stage is done on each operand individually, without regard for the other operand. (There are more rules, but this is the one that applies.)

Usual arithmetic conversions: If you compare an unsigned int against a signed int, since neither includes the entire range of the other, and both have the same rank, then both are converted to the unsigned type. This conversion is done after examining the type of both operands.

Obviously, the "usual arithmetic conversions" don't always apply, if there are not two operands. This is why there are two sets of rules. One gotcha, for example, is that shift operators << and >> don't do usual arithmetic conversions, since the type of the result should only depend on the left operand (so if you see someone type x << 5U, then the U stands for "unnecessary").

Breakdown: Let's assume a typical system with 32-bit int and 16-bit short.

int a = -1;         // "signed" is implied
unsigned b = 2;     // "int" is implied
if (a < b)
    puts("a < b");  // not printed
else
    puts("a >= b"); // printed

  1. First the two operands are promoted. Since both are int or unsigned int, no promotions are done.
  2. Next, the two operands are converted to the same type. Since int can't represent all possible values of unsigned, and unsigned can't represent all possible values of int, there is no obvious choice. In this case, both are converted to unsigned.
  3. When converting from signed to unsigned, 232 is repeatedly added to the signed value until it is in the range of the unsigned value. This is actually a noop as far as the processor is concerned.
  4. So the comparison becomes if (4294967295u < 2u), which is false.

Now let's try it with short:

short c = -1;          // "signed" is implied
unsigned short d = 2;
if (c < d)
    puts("c < d");     // printed
else
    puts("c >= d");    // not printed

  1. First, the two operands are promoted. Since both can be represented faithfully by int, both are promoted to int.
  2. Next, they are converted to the same type. But they already are the same type, int, so nothing is done.
  3. So the comparison becomes if (-1 < 2), which is true.

Writing good code: There's an easy way to catch these "gotchas" in your code. Just always compile with warnings turned on, and fix the warnings. I tend to write code like this:

int x = ...;
unsigned y = ...;
if (x < 0 || (unsigned) x < y)
    ...;

You have to watch out that any code you do write doesn't run into the other signed vs. unsigned gotcha: signed overflow. For example, the following code:

int x = ..., y = ...;
if (x + 100 < y + 100)
    ...;
unsigned a = ..., b = ...;
if (a + 100 < b + 100)
    ...;

Some popular compilers will optimize (x + 100 < y + 100) to (x < y), but that is a story for another day. Just don't overflow your signed numbers.

Footnote: Note that while signed is implied for int, short, long, and long long, it is NOT implied for char. Instead, it depends on the platform.

这篇关于为什么整型提升的结果有什么不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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