Строгое преобразование значений std :: atomic_bool - PullRequest
0 голосов
/ 16 мая 2018

У меня есть код с очень простой логической арифметикой, который включает значения, возвращенные из 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;
}

Пример кода здесь . Строка компиляции: g++ -std=c++17 -O3 -Wall -pedantic -Wconversion -pthread main.cpp && ./a.out.

Исходя из STD API, load() должен возвращать подчеркнутый тип, хранящийся в атомарном. Таким образом, flag1.load() должен возвращать bool. Однако компилятор отправляет предупреждение, что его просят преобразовать int в 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);
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Где именно это происходит? Обе стороны | преобразуются в uint16_t. Почему по-прежнему печатается предупреждение?

1 Ответ

0 голосов
/ 16 мая 2018

Обычные арифметические преобразования (как указано в § 5 стандарта ISO) определяют, что любые операнды для большинства или всех арифметических и двоичных операторов проходят целочисленное продвижение перед самой операцией.

Это означает, чточто оба uint16_t операнда сначала переводятся в int для вычисления побитового |, а затем усекаются обратно до uint16_t для хранения в r2.

На самом деле это то, о чем идет предупреждение:неявное усечение int до uint16_t.

. Эти преобразования также определяют, что bool всегда будет иметь значение 1 или 0, поэтому первое приведение бесполезно, но поскольку второй операнд будетбыть повышенным до int, тогда также второй бросок бесполезен, вы можете пойти с

uint16_t r2 = flag.load() | 0xaaff;

и, возможно, заставить замолчать предупреждение, явно приведя к более узкому типу, что заставляет вас осознать тот факт, чтоэто происходит:

uint16_t r2 = static_cast<uint16_t>(flag.load() | 0xaaff);
...