Why auto is deduced to int instead of uint16_t - c++

I have the following code:
uint16_t getLastMarker(const std::string &number);
...
const auto msgMarker = getLastMarker(msg.number) + static_cast<uint16_t>(1);
static_assert(std::is_same<decltype(msgMarker), const int>::value, "Should fail");
static_assert(std::is_same<decltype(msgMarker), const uint16_t>::value, "Should not fail");
and I expect that the first assertion will fail and second one will not. However gcc 4.9.2 and clang 3.6 do the opposite. If I use uint16_t instead of auto in my code proper assertion fails and another one succeeds.
P.S. Initially I had just 1 instead of static_cast<uint16_t>(1) and thought that the issue is caused by the fact that numeric literal 1 has type int but wrong assertion fails even after explicit cast here.

Addition will perform the usual arithmetic conversions on its operands which in this case will result in the operands being promoted to int due the the integer promotions and the result will also be int.
You can use uint16_t instead of auto to force a conversion back or in the general case you can use static_cast.
For a rationale as to why type smaller than int are promoted to larger types see Why must a short be converted to an int before arithmetic operations in C and C++?.
For reference, from the draft C++ standard section 5.7 Additive operators:
[...]The usual arithmetic conversions are performed for operands of
arithmetic or enumeration type[...]
and from section 5 Expressions:
[...]Otherwise, the integral promotions (4.5) shall be performed on
both operands.59 Then the following rules shall be applied
to the promoted operands[...]
and from section 4.5 Integral promotions (emphasis mine):
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.
Assuming int is larger than 16-bit.

Arithmetic operations don't work on any type smaller than int. So, if uint16_t is smaller than int, it will be promoted to int (or possibly a larger type, if necessary to match the other operand) before performing the addition.
The result of the addition will be the promoted type. If you want another type, you'll have to convert afterwards.

Related

What causes this signed int to unsigned int conversion using a ternary, but not shorts?

When using a ternary operator within list initialization, what causes the implicit conversion of int to unsigned int (and similarly for long long) but not short to unsigned short (and similarly for char).
Specifically, I am surprised that the i32v2 function compiles fine whereas the others do not:
unsigned short f16(unsigned short x);
unsigned int f32(unsigned int x);
void i16(short value) {
unsigned short encoded{value}; // narrowing, makes sense
}
void i32(int value) {
unsigned int encoded{value}; // narrowing, makes sense
}
void i16v2(short value) {
unsigned short encoded{false ? value : f16(value)}; // narrowing, makes sense
}
void i32v2(int value) {
unsigned int encoded{false ? value : f32(value)}; // not narrowing, huh?
}
Complete example here: https://godbolt.org/z/fVTcrr
I am guessing the ternary operator implicitly converts int to unsigned int but I do not understand why it is unable to convert short to unsigned short similarly.
I would expect, if it was possible for int, then the ternary operator should also be able to convert any of the other signed types to the unsigned when possible:
If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2n
where n is the number of bits used to represent the destination type.
(https://en.cppreference.com/w/cpp/language/implicit_conversion)
Can someone explain this behavior, and if possible, reference the standard or applicable cppreference page?
The standard says (quotes from latest draft):
[expr.cond]
Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed on the second and third operands.
After those conversions, one of the following shall hold:
The second and third operands have the same type; ... [does not apply]
The second and third operands have arithmetic [applies] or enumeration type; the usual arithmetic conversions are performed to bring them to a common type, and the result is of that type.
...
[expr.arith.conv]
Many 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:
If either operand is of scoped enumeration type ... [does not apply]
If either operand is of type long double ... [does not apply]
Otherwise, if either operand is double ... [does not apply]
Otherwise, if either operand is float ... [does not apply]
Otherwise, the integral promotions ([conv.prom]) shall be performed on both operands.
Then the following rules shall be applied to the promoted operands:
...
[conv.prom]
A prvalue of an integer type other than bool, char16_­t, char32_­t, or wchar_­t [applies] whose integer conversion rank ([conv.rank]) is less than the rank of int [applies] can be converted to a prvalue of type int if int can represent all the values of the source type [evidently applies1]; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.
These conversions are called integral promotions.
So, in the case of i16v2, the second and third operands are short and unsigned short. Both evidently1 promote to int on your system, and the int result of the conditional operator is then used to initialise the unsigned short.
In the case of i32v2, no promotions apply and the common type of int and unsigned int is unsigned int.
1 I say evidently, because technically, unsigned short could promote to unsigned int on some exotic system where their size is the same, in which case int couldn't represent all values of unsigned short. The outcome that you observe shows that is not the case for your system, which is to be expected.
Note that for false ? value : f16(value), integral_promotion is performed on the operands firstly. For arithmetic operator,
If the operand passed to an arithmetic operator is integral or unscoped enumeration type, then before any other action (but after lvalue-to-rvalue conversion, if applicable), the operand undergoes integral promotion.
and
The following implicit conversions are classified as integral
promotions:
signed char or signed short can be converted to int;
That means the return type of false ? value : f16(value) is int, then causes the narrowing conversion to unsigned short.
On the other hand, the return type, i.e. the common type for false ? value : f32(value) is unsigned int, then unsigned int encoded{false ? value : f32(value)}; is fine.
Otherwise, the operand has integer type (because bool, char, char8_t,
char16_t, char32_t, wchar_t, and unscoped enumeration were promoted at
this point) and integral conversions are applied to produce the common
type, as follows:
...
Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand
is converted to the unsigned operand's type.
For long or long long, they won't be promoted to int, then they don't have such issues.

C++ Unexpected Integer Promotion

I was writing some code recently that was actually supposed to test other code, and I stumbled upon a surprising case of integer promotion. Here's the minimal testcase:
#include <cstdint>
#include <limits>
int main()
{
std::uint8_t a, b;
a = std::numeric_limits<std::uint8_t>::max();
b = a;
a = a + 1;
if (a != b + 1)
return 1;
else
return 0;
}
Surprisingly this program returns 1. Some debugging and a hunch revealed that b + 1 in the conditional was actually returning 256, while a + 1 in assignment produced the expected value of 0.
Section 8.10.6 (on the equality/ineuqlity operators) of the C++17 draft states that
If both operands are of arithmetic or enumeration type, the usual arithmetic conversions are performed on
both operands; each of the operators shall yield true if the specified relationship is true and false if it is
false.
What are "the usual arithmetic conversions", and where are they defined in the standard? My guess is that they implicitly promote smaller integers to int or unsigned int for certain operators (which is also supported by the fact that replacing std::uint8_t with unsigned int yields 0, and further in that the assignment operator lacks the "usual arithmetic conversions" clause).
What are "the usual arithmetic conversions", and where are they defined in the standard?
[expr.arith.conv]/1
Many 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:
(1.1) If either operand is of scoped enumeration type, no conversions
are performed; if the other operand does not have the same type, the
expression is ill-formed.
(1.2) If either operand is of type long double, the other shall be
converted to long double.
(1.3) Otherwise, if either operand is double, the other shall be
converted to double.
(1.4) Otherwise, if either operand is float, the other shall be
converted to float.
(1.5) Otherwise, the integral promotions ([conv.prom]) shall be
performed on both operands.59 Then the following rules shall be
applied to the promoted operands:
(1.5.1) If both operands have the same type, no further conversion is
needed.
(1.5.2) Otherwise, if both operands have signed integer types or both
have unsigned integer types, the operand with the type of lesser
integer conversion rank shall be converted to the type of the operand
with greater rank.
(1.5.3) Otherwise, if the operand that has unsigned integer type has
rank greater than or equal to the rank of the type of the other
operand, the operand with signed integer type shall be converted to
the type of the operand with unsigned integer type.
(1.5.4) Otherwise, if the type of the operand with signed integer type
can represent all of the values of the type of the operand with
unsigned integer type, the operand with unsigned integer type shall be
converted to the type of the operand with signed integer type.
(1.5.5) Otherwise, both operands shall be converted to the unsigned
integer type corresponding to the type of the operand with signed
integer type.
59) As a consequence, operands of type bool, char8_­t, char16_­t,
char32_­t, wchar_­t, or an enumerated type are converted to some
integral type.
For uint8_t vs int (for operator+ and operator!= later), #1.5 is applied, uint8_t will be promoted to int, and the result of operator+ is int too.
On the other hand, for unsigned int vs int (for operator+), #1.5.3 is applied, int will be converted to unsigned int, and the result of operator+ is unsigned int.
Your guess is correct. Operands to many operators in C++ (e.g., binary arithmetic and comparison operators) are subject to the usual arithmetic conversions. In C++17, the usual arithmetic conversions are specified in [expr]/11. I'm not going to quote the whole paragraph here because it's rather large (you can just click on the link), but for integral types, the usual arithmetic conversions boil down to integral promotions being applied followed by effectively some more promoting in the sense that if the types of the two operands after the initial integral promotions are not the same, the smaller type is converted to the larger one of the two. The integral promotions basically mean that any type smaller than an int will be promoted to int or unsigned int, whichever of the two can represent all possible values of the original type, which is mainly what is causing the behavior in your example.
As you have already figured out yourself, in your code, the usual arithmetic conversions happen in a = a + 1; and, most noticeably, in the condition of your if
if (a != b + 1)
…
where they cause b to be promoted to int, making the result of b + 1 to be of type int, as well as a being promoted to int and the !=, thus, happening on values of type int, which causes the condition to be true rather than false…

Why does applying bitwise NOT to a char yield an int? [duplicate]

This question already has answers here:
What is going on with bitwise operators and integer promotion?
(4 answers)
Closed 6 years ago.
On my laptop, running the following code:
#include <iostream>
using namespace std;
int main()
{
char a;
cout << sizeof(~a) << endl;
}
prints 4.
I expected the result of ~a to be a char, but apparently, it is an int.
Why is that?
~ is an arithemtic operator (bitwise NOT), and a is being promoted from signed char to int (and in many implementations sizeof(int) == 4). See below for an explanation:
http://en.cppreference.com/w/cpp/language/implicit_conversion#integral_promotion
Prvalues of small integral types (such as char) may be converted to
prvalues of larger integral types (such as int). In particular,
arithmetic operators do not accept types smaller than int as
arguments, and integral promotions are automatically applied after
lvalue-to-rvalue conversion, if applicable. This conversion always
preserves the value.
The standard says (§[expr.primary]/10):
The operand of ~ shall have integral or unscoped enumeration type; the result is the one’s complement of its operand. Integral promotions are performed. The type of the result is the type of the promoted operand.
"Integral promotions" means (§[conv.prom]/1):
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.
In your case, a has type char, which has a conversion rank less than the rank of int1, so it's being promoted to either int or unsigned int, both of which have the same size (apparently 4 in your implementation).
As to why things were done this way: I think a great deal is that it just simplifies both the language definition and the compiler quite a bit. Rather than having to generate code separately for nearly every type, it does its best to collapse everything down to a few types, and most code is generated only for those types. That's not so much the case any more (now that we have multiple types larger than int), but back when C was young, the integer types were: char, short, int (and unsigned versions of those), so all the other types were promoted to int, and all code to manipulate anything was done with ints.
Note that this applied to function calls and such too: in early versions of C there were no function prototypes, so any parameter of type char or short was promoted to int before being passed to a function too.
The same basic idea was followed with floating point types: under most circumstances (including passing them to functions) floats were promoted to double, and all the actual processing was done on doubles (after which you could convert back to float, if necessary.
In case you really want the quote for that too (§[conv.rank]:
1.3 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.
[...]
1.6 The rank of char shall equal the rank of signed char and unsigned char.

Arithmetic conversion VS integral promotion

char cval;
short sval;
long lval;
sval + cval; // sval and cval promoted to int
cval + lval; // cval converted to long
This is a piece of code on C++ Primer.
I know sval+cval generates an int type according to
convert the small integral types to a larger integral type. The types
bool, char, signed char, unsigned char, short, and unsigned short are
promoted to int if all possible values of that type fit in an int.
But for the last one I couldn't understand why it uses "converted". Why is cval not promoted to int first and then the int converted (or maybe promoted I'm not sure whether promoted can be used from int to long because I only see definition of promotion on smaller type to int) to long. I didn't see any explanation or examples on char straightly to long in that part of the book. Is there any thing wrong with my understanding?
I'm quite new at C++, someone please enlighten me! Many thanks in advance!
The additive operators perform what is called the usual arithmetic conversion on their operands which can include integral promotions and then after that we can have further conversions. The purpose is to yield a common type and if the promotions do not accomplish that then a further conversion is required.
This is covered in section 5 [expr] of the draft C++ standard which says (emphasis mine):
Many 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 follow
and includes the following bullet:
Otherwise, the integral promotions (4.5) shall be performed on both operands.61 Then the following
rules shall be applied to the promoted operands:
which has the following bullets:
If both operands have the same type, no further conversion is needed
Otherwise, if both operands have signed integer types or both have unsigned integer types, the
operand with the type of lesser integer conversion rank shall be converted to the type of the
operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the
rank of the type of the other operand, the operand with signed integer type shall be converted to
the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of
the type of the operand with unsigned integer type, the operand with unsigned integer type shall
be converted to the type of the operand with signed integer type.
Otherwise, both operands shall be converted to the unsigned integer type corresponding to the
type of the operand with signed integer type.
So in the first case after promotions they both have the same type(int) so no further conversion is needed.
In the second case after promotions they do not(int and long) so a further conversion is required.
From the C++11 Standard:
4 Standard conversions
1 Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such
conversions. A standard conversion sequence is a sequence of standard conversions in the following order:
— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.
— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
— Zero or one qualification conversion.
In the expression,
cval + lval;
since cval is not of type long, it has to be converted to long. However, in the process of applying the standard conversions, integral promotion comes ahead of conversions. Hence, cval is promoted to an int first before being converted to a long.

Why is unsigned short (multiply) unsigned short converted to signed int? [duplicate]

This question already has answers here:
Implicit type conversion rules in C++ operators
(9 answers)
Closed 7 years ago.
Why is unsigned short * unsigned short converted to int in C++11?
The int is too small to handle max values as demonstrated by this line of code.
cout << USHRT_MAX * USHRT_MAX << endl;
overflows on MinGW 4.9.2
-131071
because (source)
USHRT_MAX = 65535 (2^16-1) or greater*
INT_MAX = 32767 (2^15-1) or greater*
and (2^16-1)*(2^16-1) = ~2^32.
Should I expect any problems with this solution?
unsigned u = static_cast<unsigned>(t*t);
This program
unsigned short t;
cout<<typeid(t).name()<<endl;
cout<<typeid(t*t).name()<<endl;
gives output
t
i
on
gcc version 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
gcc version 4.8.2 (GCC)
MinGW 4.9.2
with both
g++ p.cpp
g++ -std=c++11 p.cpp
which proves that t*t is converted to int on these compilers.
Usefull resources:
Signed to unsigned conversion in C - is it always safe?
Signed & unsigned integer multiplication
https://bytes.com/topic/c-sharp/answers/223883-multiplication-types-smaller-than-int-yields-int
http://www.cplusplus.com/reference/climits
http://en.cppreference.com/w/cpp/language/types
Edit: I have demonstrated the problem on the following image.
You may want to read about implicit conversions, especially the section about numeric promotions where it says
Prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int as arguments
What the above says is that if you use something smaller than int (like unsigned short) in an expression that involves arithmetic operators (which of course includes multiplication) then the values will be promoted to int.
It's the usual arithmetic conversions in action.
Commonly called argument promotion, although the standard uses that term in a more restricted way (the eternal conflict between reasonable descriptive terms and standardese).
C++11 §5/9:
” Many 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 […]
The paragraph goes on to describe the details, which amount to conversions up a ladder of more general types, until all arguments can be represented. The lowest rung on this ladder is integral promotion of both operands of a binary operation, so at least that is performed (but the conversion can start at a higher rung). And integral promotion starts with this:
C++11 §4.5/1:
” 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
Crucially, this is about types, not arithmetic expressions. In your case the arguments of the multiplication operator * are converted to int. Then the multiplication is performed as an int multiplication, yielding an int result.
As pointed out by Paolo M in comments, USHRT_MAX has type int (this is specified by 5.2.4.2.1/1: all such macros have a type at least as big as int).
So USHRT_MAX * USHRT_MAX is already an int x int, no promotions occur.
This invokes signed integer overflow on your system, causing undefined behaviour.
Regarding the proposed solution:
unsigned u = static_cast<unsigned>(t*t);
This does not help because t*t itself causes undefined behaviour due to signed integer overflow. As explained by the other answers, t is promoted to int before the multiplication occurs, for historical reasons.
Instead you could use:
auto u = static_cast<unsigned int>(t) * t;
which, after integer promotion, is an unsigned int multiplied by an int; and then according to the rest of the usual arithmetic conversions, the int is promoted to unsigned int, and a well-defined modular multiplication occurs.
With integer promotion rules
USHRT_MAX value is promoted to int.
then we do the multiplication of 2 int (with possible overflow).
It seems that nobody has answered this part of the question yet:
Should I expect any problems with this solution?
u = static_cast<unsigned>(t*t);
Yes, there is a problem here: it first computes t*t and allows it to overflow, then it converts the result to unsigned. Integer overflow causes undefined behavior according to the C++ standard (even though it may always work fine in practice). The correct solution is:
u = static_cast<unsigned>(t)*t;
Note that the second t is promoted to unsigned before the multiplication because the first operand is unsigned.
As it has been pointed out by other answers, this happens due to integer promotion rules.
The simplest way to avoid the conversion from an unsigned type with a smaller rank than a signed type with a larger rank, is to make sure the conversion is done into an unsigned int and not int.
This is done by multiplying by the value 1 that is of type unsigned int. Due to 1 being a multiplicative identity, the result will remain unchanged:
unsigned short c = t * 1U * t;
First the operands t and 1U are evaluated. Left operand is signed and has a smaller rank than the unsigned right operand, so it gets converted to the type of the right operand. Then the operands are multiplied and the same happens with the result and the remaining right operand. The last paragraph in the Standard cited below is used for this promotion.
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
-If both operands have the same type, then no further conversion is needed.
-Otherwise, if both operands have signed integer types or both have unsigned
integer types, the operand with the type of lesser integer conversion rank is
converted to the type of the operand with greater rank.
-Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.