At the advice of a high rep SO user, I've recently started compiling with the -Wconversion
flag on my codebase. This has generated quite a few warnings, some which are legitimate (needlessly adding signed
and unsigned
types, for instance), but also some head scratchers, demonstrated below:
#include <cstdint>
int main()
{
uint16_t a = 4;
uint16_t b = 5;
b += a;
return 0;
}
When I compile with g++ -Wconversion -std=c++11 -O0 myFile.cpp
, I get
warning: conversion to 'uint16_t {aka short unsigned int}' from 'int' may alter its value [-Wconversion]
b += a;
^
I've perused some similar questions on SO (dealing with |
and <<
operators), taken a look here, and have read the Numeric Promotions and Numeric Conversions sections here. My understanding is, in order to do the math, a
and b
are promoted to int
(since that's the first type that can fit the entire uint16_t
value range), math is performed, the result is written back... except the result of the math is an int
, and writing that back to uint16_t
generates the warning. The consensus of the other questions was basically to cast away the warning, and the only way I've figured out how to do that is b = (uint16_t)(b + a);
(or the equivalent b = static_cast<uint16_t>(b + a);
).
Don't want this question to get too broad, but assuming my understanding of integer promotions is correct...
int
? It seems quite odd to me that I have to cast an arithmetic result which is the same type as all the operands (guess I would expect the compiler to recognize that and suppress the warning). Historically, I've liked to use no more bits than I need, and just let the compiler handle the promotions/conversions/padding as necessary.-Wconversion
flag frequently? Just after a couple of days of using it myself, I'm starting to think its best use case is to turn it on, look at what it complains about, fix the legitimate complaints, then turn it back off. Or perhaps my definition of "legitimate complaint" needs readjusting. Replacing all of my +=
operators with spelled out casts seems like a nuisance more than anything.I'm tempted to tag this as c
as well, since an equivalent c
code compiled with gcc -Wconversion -std=c11 -O0 myFile.c
produces the exact same warning. But as is, I'm using g++
version 5.3.1 on an x86_64 Fedora 23 box. Please point me to the dupe if I've missed it; if the only answer/advice here is to cast away the warning, then this is a dupe.
int is usually (but may not be) a 32-bit signed integer, while uint16_t is guaranteed to be an unsigned 16-bit integer.
uint16_t is unsigned 16-bit integer. unsigned short int is unsigned short integer, but the size is implementation dependent. The standard only says it's at least 16-bit (i.e, minimum value of UINT_MAX is 65535 ). In practice, it usually is 16-bit, but you can't take that as guaranteed.
What's the best way to handle this moving forward?
-Wno-conversion
Or just leave it unspecified. This is just an opinion, though.
In my experience, the need for narrow integer arithmetic tends to be quite rare, so you could still keep it on for the project, and disable for the few cases where this useless warning occurs. However, this probably depends highly on the type of your project, so your experience may vary.
Should I avoid performing math on types narrower than int?
Usually yes; unless you have a specific reason to use them. "I don't need the extra bits" isn't a specific enough reason in my opinion. Arithmetic operands are promoted to int
anyway and it's usually faster and less error prone to use int
.
Just after a couple of days of using it myself, I'm starting to think its best use case is to turn it on, look at what it complains about, fix the legitimate complaints, then turn it back off.
This is quite often a useful approach to warning flags that are included in neither -Wall
nor -Wextra
such as the ones with -Wsuggest-
prefix. There is a reason why they aren't included in "all warnings".
I think this can be considered a shortcoming of gcc.
As this code doesn't generate any warning:
int a = ..., b = ...;
a += b;
This code should not generate either, because semantically they are the same (two same-type numbers are added, and the result is put into a same-type variable):
short a = ..., b = ...;
a += b;
But GCC generates a warning, because as you say, the short
's gets promoted to int
's. But the short
version isn't more dangerous as the int
one, in the sense that if the addition overflows, then the behavior is implementation-defined for the short
case, and undefined for the int
case (or if unsigned numbers are used, then truncation can happen in both cases).
Clang handles this case more intelligently, and doesn't warn for this case. I think it's because it actually tracks the possible bit-width (or maybe range?) of the result. So, for example, this warns:
int a = ...;
short b = a;
But this doesn't (but GCC warns for this):
int a = ...;
short b = a&0xf; // there is a conversion here, but clang knows that only 4 bits are used, so it doesn't warn
So, until GCC will have a more intelligent -Wconversion
, your options are:
-Wconversion
But don't hold your breath until it's fixed, there is a bug about this, opened in 2009.
A note:
Historically, I've liked to use no more bits than I need, and just let the compiler handle the promotions/conversions/padding as necessary.
If you use shorter types for storage, it's fine. But usually, there's no reason to use shorter types than int
for arithmetic. It gives no speedup (even, it can be slower, because of the unnecessary maskings).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With