从宏调用函数

时间:2015-03-26 16:00:01

标签: c c-preprocessor logarithm

您好我正在尝试创建一个宏来计算C中数字的基数2的对数。该数字应该是#defined的表的大小,如下所示。

我搜索了一下,发现这个网站包含了base2log的实现 https://graphics.stanford.edu/~seander/bithacks.html

uint8_t base2log(uint16_t value){

    uint8_t result = 0; // r will be lg(v)

    while (value >>= 1)
    {
        result++;
    }
    return result;
}

我的第一个想法是现在创建宏:

#define SIZE 256
#define BASE2LOG (base2log(SIZE))

...但这看起来不是一个非常优雅的解决方案,因为即使BASE2LOG应该在编译时定义,它仍然需要每次在代码中出现时调用一个函数。我想过可能在全局变量中分配BASE2LOG,但我确信必须有比这更简洁和正确的东西。

有办法做到这一点吗?

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

这里是一个纯宏解决方案,允许在编译时计算对数,并在C中预期整数常量表达式时使用 - 例如,当指定a的长度时(非可变长度)数组。 整数常量表达式只是编译器必须能够在编译时评估的表达式的标准。

我已经在其他地方看到了这种变体(例如Macro to compute number of bits needed to store a number n中有一个),所以我无法获得荣誉。我至少可以写出它的工作原理。

// Computes the base 2 logarithm of a 16-bit number. Meant to be used
// at compile time.
#define LOG2(n)   ((n) & 0xFF00 ? 8 + LOG2_8((n) >> 8) : LOG2_8(n))
#define LOG2_8(n) ((n) & 0xF0   ? 4 + LOG2_4((n) >> 4) : LOG2_4(n))
#define LOG2_4(n) ((n) & 0xC    ? 2 + LOG2_2((n) >> 2) : LOG2_2(n))
#define LOG2_2(n) ((n) & 0x2    ? 1 : 0)

数字的截断基数2对数只是最高1位的索引(0是最低有效位的索引)。要找到最高的1位,可以使用一种二进制搜索。

LOG2()(主宏)中,我们使用(n) & 0xFF00 ? ...来测试高字节是否包含1位。如果是,那么n中最高1位的索引是8加上n高字节内最高1位的索引。如果它不是,则最高1位的索引只是低位字节中最高1位的索引。

要获得高字节,我们执行(n) >> 8。其余的宏仅查看低字节,因此不需要屏蔽。

LOG2_8()宏计算一个字节中最高1位的索引。它使用与上述相同的逻辑,间隔减半。如果高4位包含1位,则最高1位的索引是4加上高4位内最高1位的索引。否则,它是低4位内最高位的索引。

LOG_4()的工作原理完全相同。

对于基本案例,LOG2_2(1) == 0LOG2_2(2) == 1LOG2_2(0)(在数学上未定义)恰好也变为0。

宏可以通用化,以显而易见的方式处理更大的类型。移动大于类型宽度的值是严格未定义的(不确定编译器在实践中的可靠性)并且需要注意。使其安全的一种方法是添加一个演员(假设C99 +):

#define LOG2(n)    LOG2_64((uint64_t)(n))
#define LOG2_64(n) ... /* as usual. */
...

也可以使用更简单(也有点垃圾邮件)的解决方案,例如

#define LOG2(n)   \
  ((n) < 2  ? 0 : \
   (n) < 4  ? 1 : \
   (n) < 8  ? 2 : \
   (n) < 16 ? 3 : \
   (n) < 32 ? 4 : \
   (n) < 64 ? 5 : \
   ...

(顺便提一下,C99有//式的评论,万一有人觉得有点抱怨。;)

答案 1 :(得分:2)

另一个解决方案。如果数字超过最大值,则此错误提供错误。

#define MIN_BITS(n) (1+(n>1)+(n>3)+(n>7)+(n>0x0f)+(n>0x1f)+(n>0x3f)+(n>0x7f)+   \
                    (n>0x0ff)+(n>0x1ff)+(n>0x3ff)+(n>0x7ff)+                    \
                    (n>0xfff)+(n>0x1fff)+(n>0x3fff)+(n>0x7fff)+                \
                    ((n>0xffff)?100:0))