I have a code with very simple logical arithmetic that involves values returned from std::atomic_bool
.
#include <iostream>
#include <atomic>
int main() {
uint16_t v1 = 0x1122;
uint16_t v2 = 0xaaff;
std::atomic_bool flag1(false);
uint16_t r1 = v1 | v2;
std::cout << std::hex << r1 << std::endl;
uint16_t r2 = static_cast<uint16_t>(flag1.load()) | static_cast<uint16_t>(0xaaff);
std::cout << std::hex << r2 << std::endl;
std::cout << __VERSION__ << std::endl;
}
Code example is here. Compile line: g++ -std=c++17 -O3 -Wall -pedantic -Wconversion -pthread main.cpp && ./a.out
.
Based on the STD API, load()
should return the underlined type stored in the atomic. So the flag1.load()
should be returning bool
. However, the compiler send a warning that it is asked to convert an int
to uint16_t
:
main.cpp:13:55: warning: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
uint16_t r2 = static_cast<uint16_t>(flag1.load()) | static_cast<uint16_t>(0xaaff);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Where exactly does it do this conversion? Both sides of the |
are converted to uint16_t
. Why is it still printing a warning?
Usual arithmetic conversions (as specified at §5 of ISO standard) define that any operands for most or all arithmetic and binary operators undergo integer promotion before the operation itself.
This means that both uint16_t
operands are first promoted to int
to compute the bitwise |
and then truncated back to uint16_t
to store in r2
.
Indeed that's what the warning is about: there's an implicit truncation of an int
to an uint16_t
.
These conversions also define that a bool
will always evaluate to 1 or 0, so the first cast is useless, but since the second operand will be promoted to an int
, then also the second cast is useless, you could go with
uint16_t r2 = flag.load() | 0xaaff;
and possibly silence the warning by explicitly casting to a narrower type, which makes you aware of the fact that this is happening:
uint16_t r2 = static_cast<uint16_t>(flag.load() | 0xaaff);