12

In C/C++ when I want to find sum of two chars - I get result in int.
For example:

#include <stdio.h>
int main(){
   char a = 'a', b = 'b';
   printf("%d + %d = %d\n", sizeof(a), sizeof(b), sizeof(a + b));
   return 0;
}

Prints

1 + 1 = 4

Why?

Mahnerak
  • 131
  • 1
  • 2
  • 5

7 Answers7

28

Because although a and b are each of type char, the expression a + b is of type int. Anytime you do math with char types, they are converted to int before doing the actual calculations.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
  • 5
    He knows. He's asking *why*. – David G Oct 19 '13 at 21:23
  • 11
    Because the standard says so. What other reason could there be? – Lee Daniel Crocker Oct 19 '13 at 21:24
  • 2
    There must be a reason why the standard defines it that way ;) Take a look at [this link](http://eli-project.sourceforge.net/c_html/c.html#s6.2.1.1) (or my/other answers below) for more information on integral promotion. The reason why the standard defines this, I suspect, is performance: it saves additional instructions for masking and flag promotion on architectures that define only 32b or 64b native integer types. – Jens Oct 19 '13 at 23:49
  • @LeeDanielCrocker: Per *Rationale for International Standard—Programming Languages—C*, Revision 5.10, April 2003, “Between the publication of K&R and the development of C89, a serious divergence had occurred among implementations in the evolution of integer promotion rules” and “The rules given for typing integer constants were carefully worked out in accordance with the C89 Committee’s deliberations on integer promotion rules.” So clearly there is a history behind the integer promotion rules and the committees deliberated on them, and there are reasons they are the way they are. – Eric Postpischil Oct 20 '13 at 00:57
  • @LeeDanielCrocker OK, tell us then, why the standard is so stupid for such a simple and obvious thing to do -> automatically convert result back to char after doing actual operation on ints? – ScienceDiscoverer Mar 13 '21 at 12:53
  • @Jens The question is, why not automatically convert result from int operation back to char? Programmer would be forced to do it with casts anyways, cluttering code and making it less readable. So optimization wise, it would not matter. – ScienceDiscoverer Mar 13 '21 at 12:54
4

Section 4.5 Integral promotions

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

The conversion is mandated by the standard in what is called "The usual arithmetic conversions" Clause 5 [expr] point 10:

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similarMany binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows: way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

Unless for a few select types. long double, double and float

Otherwise, the integral promotions (4.5) shall be performed on both operands.59

The (char)+(char) results in an int.

Also note that a char+char is tricky. The char can be signed or unsigned depending on implementation; so the result might easily overflow for normal values which is likely why it is not included in the standard as an exception.

Captain Giraffe
  • 14,407
  • 6
  • 39
  • 67
  • You need another quote though, this one just says the promotion is possible, you need another to actually cause it. – Ben Voigt Oct 19 '13 at 21:28
  • Also note the OP is (erroneously?) doing `sizeof(a), sizeof(b), sizeof(a + b))`, not `(char)+(char)` – paulsm4 Oct 19 '13 at 21:36
3

1) This just prints out the text string "something + something else": you're not actually adding anything: printf("%d + %d = %d\n",..)

2) sizeof(<some char>) will always be "1". That's what "sizeof()" means - it can never be anything besides "1".

3) Yes, adding type "char" (which is an integer subtype) will give an integral result.

For further details:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

The type char, the signed and unsigned integer types, and the enumerated types are collectively called integer types. The integer and real floating types are collectively called real types.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
3

Because, if not promoted, the result can overflow.

A single byte char cannot hold value greater than 255 (unsigned) or +127 (signed). When you sum two instances, there is always the possibility of overflow i.e. result exceeding 255. This means it cannot be stored in a single byte. Hence int is used which cannot over flow max sum of two chars or bytes.

fkl
  • 5,412
  • 4
  • 28
  • 68
  • 5
    But adding two `int` values can overflow, too. So by this reasoning, `int` values should be promoted to something larger for addition. That doesn't happen. Further, neither C nor C++ restricts `char` values to 8 bits. Most implementations do that, but the requirement is **at least** 8 bits. – Pete Becker Oct 19 '13 at 21:55
  • I remembered having read that some where a long time ago. It was only specific to chars when converted to ints. Following discusses this as an opinion, though i agree it does not apply to promoting all types. http://stackoverflow.com/a/4814889/986760. The one byte char was just used as an example, though it is reasonable to assume int being larger than char. – fkl Oct 21 '13 at 07:01
  • For what it's worth, here is a discussion by Raymond Chen defending overflow being among suspected reasons http://blogs.msdn.com/b/oldnewthing/archive/2004/03/10/87247.aspx – fkl Oct 21 '13 at 07:17
3

Looking at the ANSI C specification, here is how additive expressions are parsed.

More elaboration on how this is parsed and how operands are read:

The integral operand of an additive operator involving a pointer and an integer is specified to be a TypeIs_unsigned_long. Any integral type can be converted to TypeIs_unsigned_long by means of implicit conversions, so this specification is equivalent to that of the standard. The main reason for using TypeIs_unsigned_long is that OIL does not permit sets as operand specifications within a class definition, but a secondary reason is that this approach reduces the total number of operators in the compiler's database.

Jens
  • 8,423
  • 9
  • 58
  • 78
  • Um, the quoted text has nothing to do with adding two `char` values in standard C. – Pete Becker Oct 19 '13 at 21:53
  • Agreed, the quote is more concerned with adding integers and pointers; the answer is a little fuzzy. The link, however, jumps to the definition of the additive operator semantics which includes its types, and therewith the integral promotion referred to in other answers ( http://eli-project.sourceforge.net/c_html/c.html#s6.2.1.1 ). – Jens Oct 19 '13 at 23:44
2

The reason for this promotion is historical: when C was invented, 40+ years ago, processors did math on a single integral type; you could store smaller types, but there was no byte-level arithmetic. So the promotion rule reflects reality at the time: types smaller than the processor's integer type would be promoted by the hardware to that integer type. Sure, you could do the math in software (which is how long was often implemented), but that would have been much slower (as long often was).

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
1

This is how C and C++ work: before doing anything on variables of type char, the compiler converts them to int first. This is called integer promotion. Note: anything is defined by the C and C++ Standards; it doesn't include sizeof but includes most of other operations (I cannot remember any exceptions besides the sizeof one).

As to the reason for this maybe surprising behavior - this is probably a decision taken in ancient times, resulting in modern C and C++ behaving in that way since then, for compatibility.

People often had large arrays of chars, which were not really characters, but small numbers. When doing arithmetic with these, it was natural to convert each number to int automatically and doing arithmetic on these, because int is the type for which arithmetic works the fastest. There is also the pleasant side-effect that overflow is much less likely to happen when promotion is in effect (consider a*b when a and b are of char type).

In addition, printf relies on integer promotion to implement printing ASCII values for characters: printf("%d", a) expects the char-typed parameter to be promoted to int when printf is called.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • Can someone provide a hint on what is wrong about this answer (since it was downvoted)? – anatolyg Oct 20 '13 at 07:45
  • Mine was downvoted, too, without comment. Some people get a kick out of drive-by downvoting. That way they can express an opinion without the risk of having to defend it. – Pete Becker Oct 21 '13 at 12:05