【发布时间】:2012-07-02 21:55:54
【问题描述】:
考虑我想在编译时生成奇偶校验。奇偶校验计算给出了文字常量,并且使用任何体面的优化器,它本身都会归结为一个常量。现在用 C 预处理器查看以下奇偶校验计算:
#define PARITY16(u16) (PARITY8((u16)&0xff) ^ PARITY8((u16)>>8))
#define PARITY8(u8) (PARITY4((u8)&0x0f) ^ PARITY4((u8)>>4))
#define PARITY4(u4) (PARITY2((u4)&0x03) ^ PARITY2((u4)>>2))
#define PARITY2(u2) (PARITY1((u2)&0x01) ^ PARITY1((u2)>>1))
#define PARITY1(u1) (u1)
int message[] = { 0x1234, 0x5678, PARITY16(0x1234^0x5678));
这将在编译时计算奇偶校验,但它会产生大量的中间代码,扩展为表达式 u16 的 16 个实例,它本身可以是例如任意复杂的表达式。问题是 C 预处理器无法评估中间表达式,并且在一般情况下只能扩展文本(您可以强制它在原地进行整数运算,但仅适用于微不足道的情况,或者千兆字节#定义)。
我发现 3 位的奇偶校验可以通过算术表达式一次生成:([0..7]*3+1)/4。这会将 16 位奇偶校验减少为以下宏:
#define PARITY16(u16) ((4 & ((((u16)&7)*3+1) ^ \
((((u16)>>3)&7)*3+1) ^ \
((((u16)>>6)&7)*3+1) ^ \
((((u16)>>9)&7)*3+1) ^ \
((((u16)>>12)&7)*3+1) ^ \
((((u16)>>15)&1)*3+1))) >> 2))
u16仅扩展 6 次。是否有更便宜(就扩展数量而言)的方式,例如4,5等的直接公式位平价?对于范围> 3位的可接受(非溢出)值k,d,m,我找不到(x*k+d)/m形式的线性表达式的解决方案。有谁有更聪明的预处理奇偶校验计算捷径?
【问题讨论】:
-
不要使用宏,使用内联函数。这提供了您正在寻找的中间表达式评估。
-
我必须同意 mfontanini 的观点,这里最好避免使用宏。如果您使用的是 c++11,则可以使用
constexpr方法。如果您不使用 c++11 并且需要将结果作为编译时常量(不仅可能在编译时评估,而且可用作常量),请使用模板元编程在编译时评估它,否则只需使用内联函数.如果您使用纯 C,您可能希望从标签中删除 C++。 -
对不起,我也用 C++ 标记了它,不想排除他们 V8-autodrive-endless-horsepower 家伙 ;)。唉,这应该在纯 C89 环境中执行
-
C 和 C++ 是不同的语言。如果您需要一个仅适用于 C 的答案,则不应将其标记为 C++。
-
你不需要那么多&。你可以改用这个:
#define PARITY16(x) PARITY8((x) ^ ((x) >> 8))、#define PARITY8(x) PARITY4((x) ^ ((x) >> 4))、#define PARITY4(x) PARITY2((x) ^ ((x) >> 2))、#define PARITY2(x) (((x) ^ ((x) >> 1)) & 1)。
标签: c c-preprocessor compile-time parity