12

符号なし32ビット整数を格納するために必要なビット数(1..32)を返すCマクロを作成する必要があるとします。(結果はceiling(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は、コメントの1つですでに述べたようなトリックを実装しています。これをコンパイル時の式に使用する場合、これは整数定数式でなければならないため、引数を数回評価しても危険はありません。

于 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 以降) の場合、MACRO の代わりに constexpr を使用することをお勧めします。

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 に答える