Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как с помощью #define определить позицию бита
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ViKo
Хочу, например, для числа 0x0100 найти позицию бита, который в 1, то есть, получить число 8.
В-принципе, этот бит будет один (младший бит в группе), но если их несколько, нужно определить позицию младшего.
Как это сделать макрофункцией?
Тогда я смогу задавать сдвиг "магических чисел" в регистре по имени группы битов в этом регистре.
P.S. Обратная функция легко делается сдвигом 1 << NUM.
ae_
Для одного бита: log2(0x0100)=8
Не скажу за все препроцессоры, но AVRASM2 понимает такое LOG2(0x0100)
gosha-z
Цитата(ViKo @ Aug 28 2014, 16:38) *
Хочу, например, для числа 0x0100 найти позицию бита, который в 1, то есть, получить число 8.
В-принципе, этот бит будет один (младший бит в группе), но если их несколько, нужно определить позицию младшего.
Как это сделать макрофункцией?

Что-то в голову ничего, кроме вариаций на тему условного rvalue, не приходит.
Цитата(ViKo @ Aug 28 2014, 16:38) *
P.S. Обратная функция легко делается сдвигом 1 << NUM.

Вот нифига. AFAIR, стандарт не определяет используемый тип сдвига, арифметический или круговой. Так что результат, скорее, неопределенный, если не маскировать специально.
msalov
Для этих целей есть Find First Set (ffs).

Или вот ещё -> "Number of leading zeros algorithms"
ViKo
Цитата(gosha-z @ Aug 28 2014, 16:45) *
Вот нифига. AFAIR, стандарт не определяет используемый тип сдвига, арифметический или круговой. Так что результат, скорее, неопределенный, если не маскировать специально.

Шутки шутите?

Э, да ведь можно с помощью #if перебрать все варианты!
Код
#if   (VAL == 0x8000)
#define NUM 15
#elif (VAL == 0x4000)
#define NUM 14
...


А еще проще через лестницу тернарных операторов. yeah.gif
SSerge
Цитата(ViKo @ Aug 28 2014, 21:12) *
А еще проще через лестницу тернарных операторов. yeah.gif

о, а это хорошая идея.
Есть такой алгоритм, приличный С-компилятор должен это вычислить во время компиляции
Код
//calc position of rightmost nonzero bit
#define m2b(x) (\
(((x & -x) & 0x0000FFFF) ? 0 : 16)+\
(((x & -x) & 0x00FF00FF) ? 0 : 8)+\
(((x & -x) & 0x0F0F0F0F) ? 0 : 4)+\
(((x & -x) & 0x33333333) ? 0 : 2)+\
(((x & -x) & 0x55555555) ? 0 : 1)+\
((x & -x) ? 0 : 1))

Плюс в том, что это макроопределение можно использовать прямо внутри выражения.
Сергей Борщ
Правильно ли я понял: допустим у вас есть
Код
#define MASK 0x000FF0
И вы хотите из этого MASK получить 4 чтобы сделать Reg = N << 4;

Можно сделать (я делаю) так:
Код
Reg = N * (MASK & -MASK);
ViKo
Цитата(Сергей Борщ @ Aug 28 2014, 23:26) *
Правильно ли я понял:...

Да, правильно. Спасибо! Супер.
И ведь видел когда-то... rolleyes.gif
ViKo
Если описать конкретно младший бит в группе, то можно пользоваться тем же умножением, что я и сам делаю ( lol.gif показывал в другой теме). Только сомножители местами переставлены. rolleyes.gif

Код
Reg |= N * MASK_0;


Компилятор все эти умножения на сдвиги заменяет, естественно.

Цитата(SSerge @ Aug 28 2014, 18:14) *
Есть такой алгоритм, приличный С-компилятор должен это вычислить во время компиляции
...
Плюс в том, что это макроопределение можно использовать прямо внутри выражения.

Да, спасибо, макро работает, компилируется в число.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.