数字及其对数作为编译常量而无需手动更改两者?

时间:2015-03-28 15:45:13

标签: c gcc c-preprocessor

我有一个常数WIDTH,它总是2的幂,例如#define WIDTH 1024

我有一个关联的#define WIDTH_BINARY_LOG 10,我必须每次修改WIDTH时都会更改为WIDTH的二进制对数。这是不可取的,因为有时我忘了这样做,因此事情变得混乱。遗憾的是,pow()在宏中也不可用。

用法是

*z = zx >> WIDTH_BINARY_LOG

我计划解决此问题,因为WIDTH_BINARY_LOG的最大可能值为16,具体如下:

*z = zx >> BINARY_LOG(WIDTH)

具有以下定义:

#define BINARY_LOG_1        0
#define BINARY_LOG_2        1
#define BINARY_LOG_4        2
#define BINARY_LOG_8        3
#define BINARY_LOG_16       4
#define BINARY_LOG_32       5
#define BINARY_LOG_64       6
#define BINARY_LOG_128      7
#define BINARY_LOG_256      8
#define BINARY_LOG_512      9
#define BINARY_LOG_1024     10
#define BINARY_LOG_2048     11
#define BINARY_LOG_4096     12
#define BINARY_LOG_8192     13
#define BINARY_LOG_16384    14
#define BINARY_LOG_32768    15
#define BINARY_LOG_65536    16

#define BINARY_LOG(n)       BINARY_LOG_##n

#define BINARY_LOG(n)       BINARY_LOG_#n

然而,gcc在每种情况下都抱怨不已。我究竟做错了什么?假设上述方法完全不值得,其他人如何解决这个问题呢?

2 个答案:

答案 0 :(得分:3)

可以完成宏。我在代码中使用了this answer

#define WIDTH 2048

#define BINARY_LOG_1        0
#define BINARY_LOG_2        1
#define BINARY_LOG_4        2
#define BINARY_LOG_8        3
#define BINARY_LOG_16       4
#define BINARY_LOG_32       5
#define BINARY_LOG_64       6
#define BINARY_LOG_128      7
#define BINARY_LOG_256      8
#define BINARY_LOG_512      9
#define BINARY_LOG_1024     10
#define BINARY_LOG_2048     11
#define BINARY_LOG_4096     12
#define BINARY_LOG_8192     13
#define BINARY_LOG_16384    14
#define BINARY_LOG_32768    15
#define BINARY_LOG_65536    16

#define PPCAT_NX(A, B) A ## B
#define BINARY_LOG(B) PPCAT_NX(BINARY_LOG_, B)

BINARY_LOG(WIDTH)

gcc -E test.c的输出(仅宏替换阶段):

>gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 24 "test.c"
11

答案 1 :(得分:-2)

由于已有可用的答案,我想指出一些不同的解决方案:

使用constexpr(C ++ 11),可以在编译时计算从给定指数计算WIDTH。这看起来比使用宏IMHO好得多:(见c++11 fast constexpr integer powers中凯西的答案)

#include <cstdint>

constexpr int64_t ipow(int64_t base, int exp, int64_t result = 1) {
  return exp < 1 ? result : ipow(base*base, exp/2, (exp % 2) ? result*base : result);
}

int64_t foo(int64_t base, int exp) {
  return ipow(base, exp);
}