考虑我想在编译时生成奇偶校验。奇偶校验计算给出了文字常量,并且使用任何体面的优化器,它本身都会归结为一个常量。现在看一下使用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));
这将在编译时计算奇偶校验,但会产生大量的中间代码,扩展为表达式的 16 个实例,u16
其本身可以是例如任意复杂的表达式。问题是C预处理器无法评估中间表达式,并且在一般情况下只能扩展文本(您可以强制它在原位进行整数运算,但仅适用于琐碎的情况,或者使用千兆字节的#defines)。我发现 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 等的直接公式?位平价?(x*k+d)/m
对于范围 > 3 位的可接受(非溢出)值 k、d、m的形式的线性表达式,我找不到解决方案。有谁有更聪明的预处理器奇偶校验计算捷径?