2010-05-04 4 views
2

У нас есть набор макросов C, здесь, для использования препроцессора для выполнения операций с битовыми полями, и мы сталкиваемся с предупреждениями при попытке использовать эти макросы в визуальной студии. Проблема может быть продемонстрировано очень легко:Макрос вычисления битовой маски

#define BITFIELD_WIDTHMASK(Width) \ 
    ((Width) >= 32 ? ~0x0ul : (1ul << (Width)) - 1) 

unsigned long foo(void) 
{ 
    return BITFIELD_WIDTHMASK(32); 
} 

Компиляция это с MSVC дает предупреждение:

test.c(12) : warning C4293: '<<' : shift count negative or too big, undefined behavior 

Это не проблема поведения - оператор << не будет использоваться в данном случае, и это должно быть обнаружено во время компиляции. Но есть ли какие-либо предложения о том, как переписать макрос, чтобы избежать предупреждения? Или, если это не так, как перепроектировать интерфейс макроса для этого?

Заранее спасибо

ответ

3

насчет:

#define BITFIELD_WIDTHMASK(Width) \ 
    ((Width) >= 32 ? ~0x0ul : (1ul << (Width % 32)) - 1) 

?

+0

Работает и чист и плотно. Точно, что я был после. Благодаря! –

+0

Это так же эффективно, когда Width является константой. Однако, если это переменная, она может иметь более низкую эффективность выполнения, чем изменение, если это имеет значение. Все еще; охватывает все основы. +1. – Clifford

3
#define BITFIELD_WIDTHMASK(Width) (((0x80000000ul >> (32-Width)) << 1) - 1) 

Или обрабатывать ширину 0, а также просили ...

#define BITFIELD_WIDTHMASK(Width) \ 
    ((Width) >= 32 \ 
    ? ~0x0ul \ 
    : (((1ul << ((Width)/2)) << ((Width)/2)) << ((Width)&1)) - 1) 
+0

Он решает указанную проблему, но имеет аналогичную проблему при задании аргумента 'Width'' 0'. –

+0

#define BITFIELD_WIDTHMASK (Ширина) ((Ширина == 0)? 0: (Ширина == 1)? 1: (Ширина == 2)? 3: (Ширина == 3)? 7: (Ширина == 4) ? 15: ... ;-) –

+0

@Aidan Cully: Какой результат вы хотели для BITFIELD_WIDTHMASK (0)? потому что это приводит к 0xffffff (например, BITFIELD_WIDTHMASK (32)). Ваш дал ноль. Но, возможно, бит ширины нуля не имеет никакой цели. – Clifford

1

Препроцессора не компилятор вычисляет выражение, когда ширина является буквальным постоянной, и слишком глупо не оценивать обе стороны в выражении?:. Я думаю, потому что он не обрабатывает его вообще, а скорее вставляет выражение?: С постоянными операндами!

Если ширина ноль не требуется, следующее упрощение, которое работает на 1 до 32:

#define BITFIELD_WIDTHMASK(Width) (~0ul >> (32-(Width))) 

Мне кажется, что если вы знаете, ширина равна нулю, (возможно отключить функция), которая неявна, если вы используете константу с нулевым значением, было бы разумно просто использовать нуль, а не ссылаться на макрос.

+0

Это похоже на вероятность ложного предупреждения как определения OP только на другом наборе значений Width (код OP был правильным C, просто компилятор почему-то не мог видеть, что сдвиг никогда не будет оценивается, когда ширина слишком велика). – caf

+0

Вы заметите, что у моего оригинального решения был такой предел, но это не мешало компилятору предупреждать о недействительном смене. Я просто попробовал эту версию макроса с указанным мною компилятором, и он генерирует такое же предупреждение. –

+0

@Aidan Cully: Да, я просто понял, что с моей тестовой ошибкой проблема: проблема в том, что pre = процессор по-прежнему оценивает как правые выражения операндов в?: Даже когда ширина является константой.Я изменил сообщение (что может привести к тому, что действительные комментарии устарели, но просто игнорирует проблему!) – Clifford

Смежные вопросы