5

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?

akalenuk
  • 3,715
  • 4
  • 31
  • 54

6 Answers6

6

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.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
Sadique
  • 21,741
  • 6
  • 59
  • 89
6

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.

Community
  • 1
  • 1
torek
  • 330,127
  • 43
  • 437
  • 552
3

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.
Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
Dayal rai
  • 6,115
  • 19
  • 28
2

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

Juraj Blaho
  • 12,713
  • 5
  • 46
  • 92
0

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++?

Community
  • 1
  • 1
Remya Raj
  • 11
  • 4
  • 1
    Welcome to Stack Overflow. Please read the [About] page soon. I'm not really clear what your answer adds that was not already present other than the possible duplicate. Granted, as a newcomer you can't leave comments yet, but this is a fairly old question which has suddenly gained some activity. To add an answer to such a question, you normally need some important new information. – Jonathan Leffler May 08 '16 at 03:19
-1

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.

metamorphosis
  • 1,543
  • 13
  • 23
  • `i += 2` means `i = i + 2`. The right-hand side undergoes the integer promotions as described by torek's answer. `++i` means `i += 1` with similar behaviour. – M.M May 06 '16 at 01:07
  • No, it doesn't undergo that promotion. Look at the output... I'm well-aware of what they expand to. – metamorphosis May 07 '16 at 00:40
  • See C11 6.5.16.2 "A compound assignment of the form `E1 op= E2` is equivalent to the simple assignment expression `E1 = E1 op (E2)`, except that the lvalue `E1` is evaluated only once". Thus `i += 2` is exactly the same as `i = i + 2`. – M.M May 07 '16 at 06:22
  • I just SAID they were the same, you Fool. If you can't Read, don't reply. – metamorphosis May 07 '16 at 08:00
  • you said "it doesn't undergo that promotion." but it does; and your answer says that `i += 2` behaves differently to `i = i + 2` (which is false since we agree that those two are the same) – M.M May 07 '16 at 11:37
  • My answer's output shows clearly, with both code and output, that ++i and i += 1 don't generate temporaries and hence do not get promoted. You're right that I did state i = i + 2 will generate temporaries, which is False, as per the output. Amended. i = j + 2 Will generate a temporary because it has to calculate j + 2 before addition. – metamorphosis May 08 '16 at 01:06
  • IDK what you mean by "generate temporaries", but in both `i + 2` and `j + 2`, the operands undergo integer promotion. to compute, `i = i + 2` , the `i + 2` is computed first (involving promotion) and then the result is assigned to `i` (a narrowing conversion). You keep referring to your code and output but that has nothing to do with your claims. E.g. `sizeof(i += 1)` is the same as `sizeof(i)`, since the final result of compound assignment is the same as the value of the left operand afterwards; this tells you nothing about the fact that `i + 1` (with promotion) was an intermediate step. – M.M May 08 '16 at 03:22
  • Okay, I respect that you're right, but you should've said that 5 comments ago - then the discussion would've already have been over. Cheers- – metamorphosis May 09 '16 at 09:13