So, if I understood it well, integral promotion provides that: char, wchar_t, bool, enum, short
types ALWAYS are converted to int
(or unsigned int
). Then, if there are different types in an expression, further conversion will be applied.
Am I understanding this well?
And if yes, then my question: Why is it good? Why? Don't become char/wchar_t/bool/enum/short
unnecessary? I mean for example:
char c1;
char c2;
c1 = c2;
As I described before, char
ALWAYS is converted to int
, so in this case after automatic converting this looks like this:
int c1;
int c2;
c1 = c2;
But I can't understand why is this good, if I know that char
type will be enough for my needs.
The conversions you're asking about are the usual arithmetic conversions and the integer promotions, defined in section 6.3.1.8 of the latest ISO C standard. They're applied to the operands of most binary operators ("binary" meaning that they take two operands, such as
+
,*
, etc.). (The rules are similar for C++. In this answer, I'll just refer to the C standard.)Briefly the usual arithmetic conversions are:
long double
, the other operand is converted tolong double
.double
, the other operand is converted todouble
.float
, the other operand is converted tofloat
.The integer promotions are defined in section 6.3.1.1 of the C standard. For a type narrower than
int
, if the typeint
can hold all the values of the type, then an expression of that type is converted toint
; otherwise it's converted tounsigned int
. (Note that this means that an expression of typeunsigned short
may be converted either toint
or tounsigned int
, depending on the relative ranges of the types.)The integer promotions are also applied to function arguments when the declaration doesn't specify the type of the parameter. For example:
promotes the
short
value toint
. This promotion does not occur for non-variadic functions.The quick answer for why this is done is that the standard says so.
The underlying reason for all this complexity is to allow for the restricted set of arithmetic operations available on most CPUs. With this set of rules, all arithmetic operators (other than the shift operators, which are a special case) are only required to work on operands of the same type. There is no
short + long
addition operator; instead, theshort
operand is implicitly converted tolong
. And there are no arithmetic operators for types narrower thanint
; if you add twoshort
values, both arguments are promoted toint
, yielding anint
result (which might then be converted back toshort
).Some CPUs can perform arithmetic on narrow operands, but not all can do so. Without this uniform set of rules, either compilers would have to emulate narrow arithmetic on CPUs that don't support it directly, or the behavior of arithmetic expressions would vary depending on what operations the target CPU supports. The current rules are a good compromise between consistency across platforms and making good use of CPU operations.