C 宏来计算存储数字n所需的位数

C 宏来计算存储数字n所需的位数,c,macros,c-preprocessor,bits,C,Macros,C Preprocessor,Bits,假设我需要编写C宏,该宏返回存储无符号32位整数所需的位数(1..32)。(结果等于上限(log2(n)) 我需要它作为编译时计算的宏,而不是函数 我可以 #define NBITS(n) ((n)&(1<<31)?32:(n)&(1<<30)?31:... #定义NBITS(n)((n)和(1我认为C预处理器无法做到这一点。如果我没有弄错的话,你不能将预处理器If语句放在宏中。你所能做的只是一段有洞的代码,宏的参数填满了洞。#定义NBITS2(n&2

假设我需要编写C宏,该宏返回存储无符号32位整数所需的位数(1..32)。(结果等于上限(log2(n))

我需要它作为编译时计算的宏,而不是函数

我可以

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

#定义NBITS(n)((n)和(1我认为C预处理器无法做到这一点。如果我没有弄错的话,你不能将预处理器If语句放在宏中。你所能做的只是一段有洞的代码,宏的参数填满了洞。

#定义NBITS2(n&2)?1:0)
#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 <iostream>
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;
}
#定义NBITS4(n)((n&(0xC))?(2+NBITS2(n>>2)):(NBITS2(n))) #定义NBITS8(n)((n&0xF0)?(4+NBITS4(n>>4)):(NBITS4(n))) #定义NBITS16(n)((n&0xFF00)?(8+NBITS8(n>>8)):(NBITS8(n))) #定义NBITS32(n)((n&0xFFFF0000)?(16+NBITS16(n>>16)):(NBITS16(n))) #定义NBITS(n)(n==0?0:NBITS32(n)+1) #包括 使用名称空间std; int main(){
cout如果您不介意附加语句(while循环),以下语句将在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);
输出:

28
16
32
1


这可以通过一个宏来实现,该宏的测试比您在问题中提出的测试少一点,一次对多个位进行更聪明的位测试。来自的宏
P99_HIGH2
实现了一个注释中已经提到的技巧。如果这用于编译时表达式,则evaluat中没有危险这个参数必须是整数常量表达式,无论如何,

这不是C的解决方案,但是对于C++(C++ 11或更高),CistExPR而不是宏是一种方法。
constexpr int log2(unsigned int word) {     
    return word ? (1 + log2(word>>1)) : 0; 
};

如果使用-O2或-O3优化(因为递归调用),编译器将在编译时进行计算,并用文本值(例如5)替换调用(例如log2(16))在C/C++ 0x中,我可以提供一个可变的模板来做这个…C预处理器看起来不允许递归宏,ALAS.简单C++会用递归模板来做,为什么你要用宏来代替内联函数?(当然不会超过一次)-否则,如果您调用宏,例如在有副作用的函数或昂贵的函数上调用宏,则会发生不好的情况。您需要确切的位数吗?更实际的解决方案是了解存储需要多少字节,这样您就可以使用0xFF000000、0xFF0000、0xFF00和0xFF。请查看位操作的超级链接i给出了一个工作实例,它是工作的,是静态编译的,但是很长。当我给工作实例时,你怎么能认为这是不可能的?还是你要我给出完整的RHS?抱歉,我想你在谈论C++的时候,我假设你想得到宏输出,直接给你你的比特数。函数。此外,根据您的编译器优化,您可能会尝试将其放入for循环。他的宏确实提供了位数。顺便说一句,您可以将
if
语句放入宏中,但您使用它的位置必须是一个语句,在表达式中不起作用。您可以放入if语句,但不能放入#if。我在考虑optimising存储类型,在优化过程之前需要这些信息。-1:宏不会按照问题的要求扩展为编译时常量。它会,但宏会扩展为两个语句。因此,如果宏扩展为编译时常量,则无法执行类似“int arr[NBITS_32(…)]”的操作(就像Adi的解决方案一样)我思考了2秒钟后意识到:)谢谢,我会留下来作为参考,除非它得到了一系列的投票。Adi的回答似乎是Goodii认为你仍然需要1位来存储价值0。我认为这应该是C,而不是C++。对于任何好奇的人,我写了一个解释,解释了这个问题是如何解决的: