Мне немного любопытно создать макрос для создания битовой маски для регистра устройств, до 64 бит. Таким образом, BIT_MASK(31)
создает 0xffffffff
.
Однако несколько примеров C не работают так, как я думал, поскольку вместо этого я получаю 0x7fffffff
. Это так: если компилятор предполагает, что я хочу иметь подписанный вывод, а не без знака. Поэтому я попробовал 32
и заметил, что это значение возвращается к 0. Это из-за стандартов C, заявляющих, что если значение сдвига больше или равно количеству бит в переносимом операнде, тогда результат undefined. Это имеет смысл.
Но, учитывая следующую программу, bits2.c
:
#include <stdio.h>
#define BIT_MASK(foo) ((unsigned int)(1 << foo) - 1)
int main()
{
unsigned int foo;
char *s = "32";
foo = atoi(s);
printf("%d %.8x\n", foo, BIT_MASK(foo));
foo = 32;
printf("%d %.8x\n", foo, BIT_MASK(foo));
return (0);
}
Если я скомпилирую с gcc -O2 bits2.c -o bits2
и запустил его на машине Linux/x86_64, я получаю следующее:
32 00000000
32 ffffffff
Если я возьму тот же код и скомпилирую его на машине Linux/MIPS (big-endian), я получаю следующее:
32 00000000
32 00000000
На машине x86_64, если я использую gcc -O0 bits2.c -o bits2
, я получаю:
32 00000000
32 00000000
Если я настраиваю BIT_MASK
на ((unsigned int)(1UL << foo) - 1)
, то для обеих форм вывод 32 00000000
, независимо от уровня оптимизации gcc.
Итак, похоже, что на x86_64 gcc оптимизирует что-то неправильно ИЛИ undefined природа 32-битного числа слева сдвигается на 32-битное число определяется аппаратным обеспечением каждой платформы.
Учитывая все вышеизложенное, возможно ли программно создать макрос C, который создает битовую маску из одного бита или диапазона бит?
то есть:.
BIT_MASK(6) = 0x40
BIT_FIELD_MASK(8, 12) = 0x1f00
Предположим, что BIT_MASK
и BIT_FIELD_MASK
работают от 0-индекса (0-31). BIT_FIELD_MASK
заключается в создании маски из диапазона бит, т.е. 8:12
.