gpt4 book ai didi

从宏调用函数

转载 作者:太空宇宙 更新时间:2023-11-04 01:27:05 25 4
gpt4 key购买 nike

您好,我正在尝试创建一个宏来计算 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,但我确信一定有比这更简洁和合适的东西。

有办法吗?

感谢您的宝贵时间。

最佳答案

这是一个纯宏解决方案,它允许在编译时计算对数,并在 C 中需要整数常量表达式的地方使用——例如,当指定一个(非变量)的长度时长度)数组。 整数常量表达式 只是编译器必须能够在编译时求值的表达式的标准术语。

我在其他地方看到过这种变体(例如 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 有 // 风格的注释,以防有人提示。;)

关于从宏调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29283276/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com