Мне несколько любопытно создание макроса для генерации битовой маски для регистра устройства, до 64 бит. Таким образом, BIT_MASK (31)
производит 0xffffffff
.
Однако несколько примеров на C не работают должным образом, так как вместо них я получаю 0x7fffffff
. Это как если бы компилятор предполагал, что мне нужен подписанный вывод, а не беззнаковый. Итак, я попробовал 32
и заметил, что значение возвращается обратно к 0. Это связано со стандартами C, в которых говорится, что если значение сдвига больше или равно количеству бит в операнде, которое нужно сдвинуть , то результат не определен. В этом есть смысл.
Но, учитывая следующую программу, 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 что-то оптимизирует неправильно ИЛИ неопределенный характер сдвига влево 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
.