Невозможно обойти gcc -Wconversion - PullRequest
0 голосов
/ 29 января 2019
int main() {

    struct { unsigned int a:20; } s;
    unsigned int val = 0xaabbc000;

    s.a = val & 0xfffff;         // 1) works
    s.a = (val >> 12) & 0xfffff; // 2) generates -Wconversion warning
}

Я компилирую проект с -Wconversion и сталкиваюсь с ситуацией, когда не могу убедить компилятор, что я в порядке с преобразованием.

  • В случае 1 я использую то же решение, предложенное в битовых полях c ++ и -Wconversion , и оно прекрасно работает.Это заставляет компилятор принять преобразование из-за битовой маски, которая ограничивает диапазон значений.

  • Однако в случае 2 из-за сдвига (но почему?) Компилятор отказывается принятьпреобразование.И жалуется следующим образом:

    $ gcc wconv.c -Wconversion -Werror
    wconv.c: In function ‘main’:
    wconv.c:8:11: error: conversion to ‘unsigned int:20’ from ‘unsigned int’ may alter its value [-Werror=conversion]
     s.a = (val >> 12) & 0xfffff; // 2) generates -Wconversion warning
           ^
    cc1: all warnings being treated as errors
    

    (Интересное примечание: при использовании clang код компилируется без проблем. До сих пор я наблюдал, что -Wconversion в clang гораздо менее строг, чем в GCC).

Вопросы:

  • Как я могу убедить GCC скомпилировать вариант 2?
  • Но также, почему это смещение вправоизменить все?В моем понимании, учитывая выражение, имеющее тип unsigned int, операция сдвига битов не должна изменять его тип.
  • И, наконец, может ли это быть ошибка компилятора?

Примечание [1] : этот вопрос , а не , является дубликатом: битовых полей c ++ и -Wconversion , потому что предлагаемые там решения просто не работают в моем случае.

Примечание [2] : этот вопрос не , дубликат: Почему >> 24 вызывает -Wconversion, но >> 23 нет? Потому что относится к другой ошибке (или другому проявлению одной и той же основной ошибки) и имеет простой обходной путь, использующий приведение, как предложено в c ++ битовых полях и -Wconversion , вменьше всего с GCC 7.3.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

A ... обходной путь: используйте временную переменную.Не идеально, но это избавляет от предупреждения

const unsigned t = val >> 12u;
s.a = t & 0xfffffu;

Кроме того, вы можете явно включить предупреждение для строки:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
    s.a = (val  >> 12u) & 0xfffffu;
#pragma GCC diagnostic pop
0 голосов
/ 31 января 2019

Я только что обнаружил, что в трекере ошибок GCC есть несколько ошибок, связанных с -Wconversion.В частности: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170

В частности, комментарий #18 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170#c18) приводит пример, почти идентичный моему:

#include <stdint.h>

struct foo
{
   unsigned bar: 30;
   unsigned fill: 2;
};

struct foo test(uint32_t value)
{
   struct foo foo;

   foo.bar = (value >> 2) & 0x3fffffffU;

   return foo;
}

Поэтому я считаю, что эта проблемаокончательно gcc bug .

Персональный обходной путь

Учитывая ошибку компилятора, мой персональный обходной путь состоял в том, чтобы просто обернуть операцию сдвига вправо в функции static always_inlineдаже если я не особенно доволен этим взломом.

#include <stdint.h>

static __attribute__((always_inline)) inline uintptr_t
rshift(uintptr_t val, uintptr_t bits)
{
   return val >> bits;
}

int main() {

    struct { unsigned int a:20; } s;
    unsigned int val = 0xaabbc000;

    s.a = val & 0xfffff;                // 1) works
    s.a = (rshift(val, 12)) & 0xfffff;  // 2) works
}

Обходной путь, предложенный PSkocik

   s.a = (unsigned){(val >> 12)} & 0xfffff; // works

Который сейчас мой любимый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...