Перейти к содержанию
    

GCC Warning: left shift count >= width of type

Компилирую следующий код:

 

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 константа (что видно по листингу).

Как убрать это сообщение?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для 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;
    }
};

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для 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);
            ...
        }
    };
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

            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 всё красиво):

#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); }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

LPC17 ?

Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки if (shift < 32)).

Он самый! :)

 

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

Здорово, такой вариант мне больше нравится :) Попробую использовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...