Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: GCC Warning: left shift count >= width of type
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Pavel V.
Компилирую следующий код:

Код
template<uint32_t pin>
class Pin
{
public:
    void Test()
    {
        if(pin < 16) {
1:            g_test &= ~(0x03UL << (pin * 2));
        }
        else
        {
            g_test &= ~(0x03UL << ((pin - 16) * 2));
        }
    }
};

int main()
{
    Pin<22> test;
    test.Test();
}


На строчку 1 компилятор ругается:

Код
source/main.cpp: In member function 'void Pin<pin>::Test() [with long unsigned int pin = 22ul]':
source/main.cpp:30:12:   instantiated from here
source/main.cpp:18:4: warning: left shift count >= width of type [enabled by default]


Код компилируется и работает правильно. Оптимизатор, естественно, выкидывает ненужный код, т.к. pin константа (что видно по листингу).
Как убрать это сообщение?
_Артём_
А g_test - это кто?
neiver
Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для pin < 16 и для pin >= 16.
Код
template<uint32_t pin>
class Pin
{
// warning: brain-compiled code ahead
   template<bool pinLessThen16>
   struct Mask
   {
      enum {value =  ~(0x03UL << (pin * 2)) };
   };

   template<>
   struct Mask<false>
   {
      enum {value =  ~(0x03UL << ((pin - 16) * 2)) };
   };

public:
    void Test()
    {
      g_test &= Mask<(pin < 16)>::value;
    }
};
Pavel V.
Цитата(neiver @ Feb 11 2012, 00:27) *
Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для pin < 16 и для pin >= 16.

Спасибо за идею! В итоге так и сделал, только использовал анонимный параметр, что избавило от необходимости в вызове писать условие pin < 16.
Специализацию шаблона нельзя выполнять внутри класса, поэтому вынес наружу.

Код
namespace IO
{
    template<uint32_t pin, bool = (pin < 16)>
    struct ConfigurationMask
    {
        static inline uint32_t Clear() { return ~(0x03UL << (pin * 2)); }
        static inline uint32_t SelSet(Configuration configuration) { return (((uint32_t)configuration >> 4) & 0x03UL) << (pin * 2); }
        static inline uint32_t ModeSet(Configuration configuration) { return (((uint32_t)configuration >> 2) & 0x03UL) << (pin * 2); }
    };

    template<uint32_t pin>
    struct ConfigurationMask<pin, false>
    {
        static inline uint32_t Clear() { return ~(0x03UL << ((pin - 16) * 2)); }
        static inline uint32_t SelSet(Configuration configuration) { return (((uint32_t)configuration >> 4) & 0x03UL) << ((pin - 16) * 2); }
        static inline uint32_t ModeSet(Configuration configuration) { return (((uint32_t)configuration >> 2) & 0x03UL) << ((pin - 16) * 2); }
    };

    template<Port port, uint32_t pin, ActiveState activestate>
    class Pin
    {
        static_assert((pin < 32), "Pin number must be <= 31");

    public:
        /*
         * Set Configuration
         */
        static void SetConfiguration(Configuration configuration)
        {
            ...
            SEL0 &= ConfigurationMask<pin>::Clear();
            SEL0 |= ConfigurationMask<pin>::SelSet(configuration);
            MODE0 &= ConfigurationMask<pin>::Clear();
            MODE0 |= ConfigurationMask<pin>::ModeSet(configuration);
            ...
        }
    };
}
ReAl
Цитата(Pavel V. @ Feb 11 2012, 18:11) *
Код
            SEL0 &= ConfigurationMask<pin>::Clear();
            SEL0 |= ConfigurationMask<pin>::SelSet(configuration);
            MODE0 &= ConfigurationMask<pin>::Clear();
            MODE0 |= ConfigurationMask<pin>::ModeSet(configuration);
LPC17 ?
Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки if (shift < 32)).
Код
        if (shift < 32) {
            LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x03 << shift))
                             | (CLKPWR_PCLKSEL_CCLK_DIV_1 << shift);
        } else {
            LPC_SC->PCLKSEL1 = (LPC_SC->PCLKSEL1 & ~(0x03 << (shift-32)))
                             | (CLKPWR_PCLKSEL_CCLK_DIV_1 << (shift-32));
        }

Сначала по-быстрячку сделал shift локальной переменной функции. Оптимизатор всё делает нормально, а предупреждение пропадает. Потом нарисовал такое (в рабочий код ещё не интегрировал, в тесте с ключиком -S всё красиво):
CODE
#include <stdint.h>

template<unsigned width, unsigned position, unsigned reg_bits = 32>
struct field_traits
{
enum {
reg_index = position / reg_bits,
shift = position % reg_bits,
unshifted_mask = (1UL << width) - 1,
mask = unshifted_mask << shift
};
static unsigned value(unsigned val) { return (val & unshifted_mask) << shift; }
static unsigned place(unsigned reg) { return reg & ~mask; }
static unsigned insert(unsigned reg, unsigned val) { return place(reg) | value(val); }
};

struct params {
volatile uint32_t reg0, reg1;
};

params p;

template<unsigned pin>
struct tst
{
typedef field_traits<2, 2*pin> traits;
static void Setup(unsigned v)
{
#if 1
traits::reg_index == 0 ? p.reg0 = traits::insert(p.reg0,v)
: p.reg1 = traits::insert(p.reg1,v);
#else
// Имея уверенность (или при соответствующем описании целевой структуры)
// можно и так:
volatile uint32_t *preg = &p.reg0 + traits::reg_index;
*preg = traits::insert(*preg,v);
#endif
}
};


typedef tst<1> tst1;
typedef tst<15> tst15;
typedef tst<16> tst16;
typedef tst<18> tst18;
typedef tst<31> tst31;

void foo1() { tst1::Setup(0); }
void foo15() { tst15::Setup(1); }
void foo16() { tst16::Setup(2); }
void foo18() { tst18::Setup(2); tst18::Setup(1);}
void foo31() { tst31::Setup(3); }
Pavel V.
Цитата(ReAl @ Feb 12 2012, 15:32) *
LPC17 ?
Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки if (shift < 32)).

Он самый! sm.gif

Цитата(ReAl @ Feb 12 2012, 15:32) *
Сначала по-быстрячку сделал shift локальной переменной функции. Оптимизатор всё делает нормально, а предупреждение пропадает. Потом нарисовал такое (в рабочий код ещё не интегрировал, в тесте с ключиком -S всё красиво):

Здорово, такой вариант мне больше нравится sm.gif Попробую использовать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.