可以设计一个宏,在编译时执行CRC计算。类似于
//选择短且独特的名称。
#define cZX((n),b,v) (((n) & (1 << b)) ? v : 0)
#define cZY((n),b, w,x,y,z) (cZX((n),b,w)^CzX((n),b+1,x)^CzX((n),b+2,y)^cZX((n),b+3,z))
#define CRC(n) (cZY((n),0,cZ0,cZ1,cZ2,cZ3)^cZY((n),4,cZ4,cZ5,cZ6,cZ7))
应该可以工作,并且如果
(n)
可以被评估为编译时常量,则非常高效;它将简单地评估为一个常量本身。另一方面,如果
n
是一个表达式,则该表达式最终会被重新计算8次。即使
n
是一个简单的变量,生成的代码也可能比写成最快的非基于表格的方式要大得多,并且可能比写成最紧凑的方式要慢。
顺便说一下,我真的希望在C和C ++标准中能够指定重载的方法,仅在特定参数可以评估为编译时常量时才使用这些方法。语义将是这样的:不保证任何这样的重载将在每种情况下都被使用,但是保证(1)在必须在运行时评估“编译时常量”参数的任何情况下都不会使用此类重载,以及(2)在其中一个这样的重载中被视为常量的任何参数将在从其中调用的任何函数中被视为常量。有很多情况下,如果其参数是常量,则可以编写函数以计算为编译时常量,但其中运行时评估将是绝对可怕的。例如:
#define bit_reverse_byte(n) ( (((n) & 128)>>7)|(((n) & 64)>>5)|(((n) & 32)>>3)|(((n) & 16)>>1)|
(((n) & 8)<<1)|(((n) & 4)<<3)|(((n) & 2)<<5)|(((n) & 1)<<7) )
#define bit_reverse_word(n) (bit_reverse_byte((n) >> 8) | (bit_reverse_byte(n) << 8))
在PIC上,一个简单的非循环单字节位反转函数的渲染大约需要17-19个单周期指令;一个字(16位)位反转需要34个指令,或者大约10个加上一个字节反转函数(执行两次)。最优汇编代码为反转字节需要15个单周期指令,反转字则需要17个。计算一些字节变量b
的bit_reverse_byte(b)
将需要数十条指令,总共需要数十个周期。计算一些16位字w
的bit_reverse_word(w)
可能需要数百条指令,需要数百或数千个周期才能执行。如果可以像上面的公式那样标记一个函数以扩展内联,当它扩展为四条指令时(基本上只是加载结果),这将非常好,但在内联扩展会很麻烦的情况下使用函数调用。