Strange GCC short int conversion warning

2019-02-22 12:48发布

I have a bit of C code, which goes exactly like this:

short int fun16(void){
    short int a = 2;
    short int b = 2;
    return a+b;
}

When I try to compile it with GCC, I get the warning:

warning: conversion to 'short int' from 'int' may alter its value [-Wconversion]
  return a+b;
          ^

Though there is no visible conversion. Both operands are short and even the returning value is short as well. So, what's the catch?

6条回答
聊天终结者
2楼-- · 2019-02-22 13:15

GCC will only perform these implicit upscaling to int on operations which generate temporaries:

++i
i += 2

will not generate temporaries.

i = j + 1

will.

The following code:

std::cout << sizeof(i) << " "
<< sizeof(i + 1) << " " 
<< sizeof(i + static_cast<unsigned short>(1)) << " " 
<< sizeof(static_cast<unsigned short>(i) + static_cast<unsigned short>(1)) << " " 
<< sizeof(++i) << " " 
<< sizeof(i + 0x0F) << " " 
<< sizeof(i += 1) << std::endl;

Will give the following output in either release or debug modes: 2 4 4 4 2 4 2

Indicating that while some things may suppress the warning, they don't actually stop the compiler upscaling to int. So to lose the warning, stop the generation of temporaries.

查看更多
聊天终结者
3楼-- · 2019-02-22 13:23

When you do arithmetic computations, the operands are subject to "the usual arithmetic conversions" (a superset of the "integer promotions" quoted in Acme's answer—he beat me to this but I'll go ahead and post anyway :-) ). These widen short int to plain int, so:

a + b

computes the same result as:

((int) a) + ((int) b)

The return statement must then narrow this int to a short int, and this is where gcc produces the warning.

查看更多
仙女界的扛把子
4楼-- · 2019-02-22 13:26

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

Refer the following post: Why must a short be converted to an int before arithmetic operations in C and C++?

查看更多
Deceive 欺骗
5楼-- · 2019-02-22 13:28

Quoting the standard (§6.3.1.1 ¶2):

The following may be used in an expression wherever an int or unsigned int may be used:

  • An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • A bit-field of type _Bool, int, signed int, or unsigned int.

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

The -Wconversion flag warns about:

Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like abs (x) when x is double; conversions between signed and unsigned, like unsigned ui = -1; and conversions to smaller types, like sqrtf (M_PI). Do not warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or if the value is not changed by the conversion like in abs (2.0). Warnings about conversions between signed and unsigned integers can be disabled by using -Wno-sign-conversion.

查看更多
可以哭但决不认输i
6楼-- · 2019-02-22 13:33

From The C Programming Language section 2.7 Type Conversion

  • If either operand is long double, convert the other to long double.
  • Otherwise, if either operand is double, convert the other to double.
  • Otherwise, if either operand is float, convert the other to float.
  • Otherwise, convert char and short to int.
  • Then, if either operand is long, convert the other to long.
查看更多
forever°为你锁心
7楼-- · 2019-02-22 13:37

When both operands are short, they are implicitly promoted to int in arithmetic operations.

查看更多
登录 后发表回答