Zajmuję się hakowaniem mikro-kontrolerów i podczas gdy jestem bardzo zadowolony z operatorów bitowych i mówię wprost do sprzętu, znajduję wynikowy kod bardzo obszerny i szablonowy. Wyższy poziom programisty we mnie chce znaleźć skuteczny, ale skuteczny sposób, aby to wyczyścić.Makr preprocesora C do spakowania bitfieldów do bajtu?
Na przykład, istnieje wiele ustawień flagi w rejestrach:
/* Provided by the compiler */
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 5
#define CPOL 4
#define CPHA 3
void init_spi() {
SPCR = (1 << SPE) | (1 << SPIE) | (1 << MSTR) | (1 << SPI2X);
}
szczęście istnieją makra, które ukrywają rzeczywiste operacje portów IO (po lewej stronie), więc wygląda na to proste zadanie. Ale cała ta składnia jest dla mnie brudna.
Wymagania są następujące:
- ma tylko obsłużyć do 8 bitów,
- bit pozycji musi być przekazywana w dowolnej kolejności, a
- powinny wymagać ustawione tylko bity być minęło.
Składnia ja jak to:
SPCR = bitów (SPE Spie MSTR, SPI2X);
Najlepszym Mam wymyślić tak daleko to combo makro/funkcja:
#define bits(...) __pack_bits(__VA_ARGS__, -1)
uint8_t __pack_bits(uint8_t bit, ...) {
uint8_t result = 0;
va_list args;
va_start(args, bit);
result |= (uint8_t) (1 << bit);
for (;;) {
bit = (uint8_t) va_arg(args, int);
if (bit > 7)
break;
result |= (uint8_t) (1 << bit);
}
}
To kompiluje do 32 bajtów na moim szczególnym architecure i trwa 61-345 cykli do wykonania (w zależności od tego, ile bitów zostały przekazane).
Idealnie należy to zrobić w preprocesorze, ponieważ wynik jest stałą, a instrukcje maszyny wyjściowej powinny być po prostu przypisaniem 8-bitowej wartości do rejestru.
Czy można to zrobić lepiej?
To chyba to, co bym zrobił, gdyby nie definicji pozycji bitowej już zdefiniowane przez architekturę ukierunkowane wsparcie kompilatora (w tym przypadku avr-gcc). Całkiem głupi myślę. Jeśli jest gdziekolwiek, muszą być użyte inaczej niż jako argument z przesunięciem w lewo ... Nie mogę tego znaleźć. Ale tak właśnie jest. –
Również kod, który widziałem do tej pory, zmienia się przy użyciu formularza 1 << XX i przy użyciu _BV (XX). _BV jest dostarczonym makro, które ma (1 << n). Ale to nadal oznacza zbyt dużo pisania. –
dobry pomysł. ale ze względów bezpieczeństwa dodałbym kilka nawiasów wokół n #define BIT (n) (1 << (n)) wiesz, makra mogą być nieprzyjemne. wyobraź sobie kogoś używającego makra z BIT (5-1) ... – Roland