Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ warning: conversion to uint16_t from int may alter its value

Tags:

c++

g++

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...

  1. What's the best way to handle this moving forward? Should I avoid performing math on types narrower than 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.
  2. Anyone use -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.

like image 677
yano Avatar asked Nov 29 '17 00:11

yano


People also ask

What is the difference between int and uint16_t?

int is usually (but may not be) a 32-bit signed integer, while uint16_t is guaranteed to be an unsigned 16-bit integer.

What does uint16_t mean?

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.


2 Answers

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".

like image 68
eerorika Avatar answered Sep 20 '22 09:09

eerorika


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:

  1. don't use -Wconversion
  2. fix all the warnings it prints
  3. use clang instead (maybe for GCC: turn off this warning; and for clang: turn it on)

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).

like image 44
geza Avatar answered Sep 19 '22 09:09

geza