假设我需要编写一个C宏,返回存储32位无符号整数所需的位数(1..32)。 (结果等于上取整(log2(n))。
我需要将其作为编译时计算的宏,而不是函数实现。
我可以这样做:
#define NBITS(n) ((n)&(1<<31)?32:(n)&(1<<30)?31:...
它能正常工作,但是有点长。(这里速度不重要,计算在编译时完成)。
有没有更短的方法来编写这个宏?最短的方法?
假设我需要编写一个C宏,返回存储32位无符号整数所需的位数(1..32)。 (结果等于上取整(log2(n))。
我需要将其作为编译时计算的宏,而不是函数实现。
我可以这样做:
#define NBITS(n) ((n)&(1<<31)?32:(n)&(1<<30)?31:...
它能正常工作,但是有点长。(这里速度不重要,计算在编译时完成)。
有没有更短的方法来编写这个宏?最短的方法?
#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;
}
这好吗?
这可以通过使用比您在问题中提出的更聪明的位测试,使用一种执行少量测试的宏来完成。宏P99_HIGH2
来自P99,实现了一种技巧,正如其中一个评论中已经提到的那样。如果将其用于编译时表达式,则多次评估参数没有危险,因为这必须是整数常量表达式。
如果您不介意添加额外的语句(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
这不是 C 语言的解决方案,而是针对 C++ (c++11 或更高版本)的解决方案,使用 constexpr 而不是 MACRO 是一个好办法。
constexpr int log2(unsigned int word) {
return word ? (1 + log2(word>>1)) : 0;
};
我认为C预处理器无法做到这一点。如果我没有弄错的话,您不能在宏中放置预处理器if语句。您所能做的就是编写一个带有空缺的代码片段,使用宏的参数填充这些空缺。
if
语句,但是你使用它的地方必须是一个语句,不能在表达式中使用。 - Karoly Horvath