char toupper(char c) {
if (c >= 'a' && c <= 'z') {
return (c - 'a') + 'A';
else { return c; }
}In C++, 'a' is a char and the comparison result is a bool, though it doesn't really make a difference in that function.
toUpper(char) -> $ + char. % It's "$ " (c - 'a') + 'A'
contains both (c + 'A') - 'a'
to make this more clear, but I think that's actually UB with signed chars- e.g. for c='a', 'a'+'A' exceeds the range of a signed 8-bit value!Promotion should save us here, but that's a bit too yikes-y for my comfort.
char + char = invalid
char + offset = offset + char = char
offset + offset = offset
char - char = offset
char - offset = char
offset - char = invalid
offset - offset = offset
Given that, (c - 'a') + 'A' is perfectly valid without adding two characters.
edit: formatting
A multiplication `uint16_t * uint16_t` can still cause an overflow after promotion to signed int, which is undefined behavior! So "unsigned types wrap around" doesn't apply to `uintN_t`, because you can never know for sure whether those types are "smaller than int" and thus get promoted to signed types when you do any arithmetic.
Of course, in practice this just means: every C and C++ program relies on tons of implementation-defined behavior. A `sizeof(int)` greater than 32-bits would break most code in existence (e.g. hash code computations using `uint32_t`).
Last time similar thing bit me was when the platform had 16-bit int... so just adding two int16_t can very well cause int overflow.
You can deduce the width (number of sign + value bits) of the standard integer types from their limits (e.g. INT_MAX, INT_MIN, etc). The problem has been that this is non-trivial if not impossible to do from the preprocessor. The next C standard will include width constants (e.g. INT_WIDTH) for the standard integer types.
(In C++, you of course have operator overloading, that's how std::string concat sugar works.)
'1' + '1' == 'b'. Because 49 + 49 == 98. ASCII '1' == 49, and 'b' == 98.