12

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

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

我可以

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

它有效,但相当长。(速度在这里并不重要,计算是在编译时)。

有没有更短的方法来编写这个宏?最短?

4

5 回答 5

10
#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;
}

这很好?

于 2011-07-26T19:28:02.853 回答
0

这可以通过一个比您在问题中建议的测试少一点的宏来完成,方法是一次对几个位使用更聪明的位测试。P99中的宏实现P99_HIGH2了一个评论中已经提到的技巧。如果这用于编译时表达式,则多次评估参数是没有危险的,因为无论如何这必须是一个整数常量表达式。

于 2011-07-26T19:42:50.647 回答
0

如果您不介意附加语句(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

于 2011-07-26T19:28:47.887 回答
0

这不是 C 的解决方案,但对于 C++(c++11 或更高版本), constexpr 而不是 MACRO 是一种方法。

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

如果使用了-O2 或-O3 优化(因为递归调用),编译器将在编译时进行评估并将调用(例如log2(16))替换为文字值(例如5)。

于 2016-04-04T22:39:12.930 回答
-3

我不认为 C 预处理器能够做到这一点。如果我没记错的话,您不能将预处理器 if 语句放在宏中。你所能做的就是一段带孔的代码,用宏的参数填充孔。

于 2011-07-26T18:46:22.467 回答