Macro pour calculer le nombre de bits nécessaires pour stocker un nombre n

Disons que je dois écrire une macro C qui renvoie le nombre de bits (1..32) nécessaires pour stocker un entier 32 bits non signé. (Le résultat est égal au plafond (log2 (n)).

J’en ai besoin comme macro calculée au moment de la compilation, pas comme une fonction.

je pourrais faire

#define NBITS(n) ((n)&(1<<31)?32:(n)&(1<<30)?31:... 

ça marche, mais c’est plutôt long. (La vitesse n’a pas d’importance ici, le calcul est au moment de la compilation).

Y at-il moyen plus court d’écrire cette macro? Le plus court?

 #define NBITS2(n) ((n&2)?1:0) #define NBITS4(n) ((n&(0xC))?(2+NBITS2(n>>2)):(NBITS2(n))) #define NBITS8(n) ((n&0xF0)?(4+NBITS4(n>>4)):(NBITS4(n))) #define NBITS16(n) ((n&0xFF00)?(8+NBITS8(n>>8)):(NBITS8(n))) #define NBITS32(n) ((n&0xFFFF0000)?(16+NBITS16(n>>16)):(NBITS16(n))) #define NBITS(n) (n==0?0:NBITS32(n)+1) #include  using namespace std; int main(){ cout << NBITS(0) << endl; cout << NBITS(1) << endl; cout << NBITS(2) << endl; cout << NBITS(3) << endl; cout << NBITS(4) << endl; cout << NBITS(1023) << endl; cout << NBITS(1024) << endl; } 

c'est bon?

Si cela ne vous dérange pas des instructions supplémentaires (while loop), ce qui suit fonctionnera dans c99

 #define NBITS_32(n,out_len) 0; while (n && !(0x80000000 >> out_len & n)) out_len++; out_len = n ? abs(out_len - 32) : n uint8_t len1 = NBITS_32(0x0F000000, len1); uint8_t len2 = NBITS_32(0x00008000, len2); uint8_t len3 = NBITS_32(0xFFFFFFFF, len3); uint8_t len4 = NBITS_32(0x00000001, len4); printf("%u\n%u\n%u\n%u\n", len1, len2, len3, len4); 

Sortie:

28
16
32
1

Cela peut être fait avec une macro qui teste un peu moins que ce que vous proposez dans votre question, en utilisant un bit plus astucieux pour tester plusieurs bits à la fois. La macro P99_HIGH2 de P99 met en oeuvre une astuce déjà évoquée dans l’un des commentaires. Si ceci est utilisé pour les expressions de temps de compilation, l’évaluation de l’argument à plusieurs resockets est sans danger, car il doit s’agir d’une expression constante entière, de toute façon.

Ce n’est pas une solution pour C, mais pour C ++ (c ++ 11 ou supérieur), constexpr au lieu de MACRO est une solution.

 constexpr int log2(unsigned int word) { return word ? (1 + log2(word>>1)) : 0; }; 

Le compilateur effectuera l’évaluation au moment de la compilation et remplacera l’appel (par exemple, log2 (16)) par une valeur littérale (par exemple, 5), à condition que l’optimisation -O2 ou -O3 soit utilisée (en raison de l’appel récursif).

Je ne pense pas que le préprocesseur C puisse le faire. Si je ne me trompe pas, vous ne pouvez pas placer les instructions preprocessor if dans une macro. Tout ce que vous pouvez faire est un morceau de code avec des trous, avec les parameters de la macro remplissant les trous.