简体   繁体   中英

Strange GCC short int conversion warning

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?

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 .

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.

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 .

当两个操作数都很short ,它们在算术运算中被隐式提升为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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM