考虑到我想在编译时生成parities。奇偶校验计算是给定的文字常量,使用任何合适的优化器,它都可以归结为单个常量本身。现在看一下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))

只膨胀了6倍有没有一种更便宜的方法(就扩展次数而言),例如4,5位奇偶校验的直接公式?对于可接受(非溢出)值k,d,m(范围>3位),我找不到形式为u16的线性表达式的解决方案有谁有更聪明的预处理器奇偶校验计算的捷径吗?

最佳答案

你在找这样的东西吗?
下面的“PARIIT16(U16)”预处理器宏可以用作结构赋值中的文字常量,它只对参数进行一次求值。

/* parity.c
 * test code to test out bit-twiddling cleverness
 * 2013-05-12: David Cary started.
*/

// works for all 0...0xFFFF
// and only evalutes u16 one time.
#define PARITYodd33(u33) \
    ( \
        ((((((((((((((( \
            (u33) \
        &0x555555555)*5)>>2) \
        &0x111111111)*0x11)>>4) \
        &0x101010101)*0x101)>>8) \
        &0x100010001)*0x10001)>>16) \
        &0x100000001)*0x100000001)>>32) \
    &1)
#define PARITY16(u16) PARITYodd33(((unsigned long long)u16)*0x20001)

// works for all 0...0xFFFF
// but, alas, generates 16 instances of u16.
#define PARITY_16(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 message1[] = { 0x1234, 0x5678, PARITY16(0x1234^0x5678) };
int message2[] = { 0x1234, 0x5678, PARITY_16(0x1234^0x5678) };

#include <stdio.h>

int main(void){
        int errors = 0;
        int i=0;
        printf(" Testing parity ...\n");
        printf(" 0x%x = message with PARITY16\n", message1[2] );
        printf(" 0x%x = message with PARITY_16\n", message2[2] );
        for(i=0; i<0x10000; i++){
                int left = PARITY_16(i);
                int right =  PARITY16(i);
                if( left != right ){
                        printf(" 0x%x: (%d != %d)\n", i, left, right );
                        errors++;
                        return 0;
                };
        };
        printf(" 0x%x errors detected. \n", errors );
} /* vim: set shiftwidth=4 expandtab ignorecase : */

与您发布的原始代码非常相似,它将位配对,并(实际上)计算每对位之间的异或,然后根据结果再次将位配对,每次将位数减半,直到只剩下一个奇偶校验位。
但这真的是你想要的吗?
许多人说他们正在计算一条信息的“对等”。
但以我的经验来看,大多数时候他们真的
aerror-detection code大于单个奇偶校验位--
aLRC或aCRC或aHamming code等。
更多细节
如果当前系统在合理的时间内编译,
它给出了正确的答案,我不会管它。
重构“预处理器如何生成某些常量”
将以相同的运行时可执行文件逐位生成。
我宁愿有易读的资料
即使编译需要整整一秒钟的时间。
许多人使用比标准C预处理器更容易阅读的语言来生成C源代码。
参见pycrccharacter set extractor"using Python to generate C"等。
如果当前系统需要很长时间才能编译,
而不是调整C预处理器,
我很想把这个消息,包括奇偶校验,放在一个单独的“.h”文件中
使用硬编码常量(而不是每次强制C预处理器计算它们),
在嵌入式系统的“.c”文件中包含“.h”文件。
然后我将制作一个完全独立的程序(可能是用C或Python编写的)
奇偶性计算和
打印出“.h”文件的内容作为预计算的C源代码,
有点像
print("int message[] = { 0x%x, 0x%x, 0x%x };\n",
    M[0], M[1], parity( M[0]^M[1] ) );

调整myMAKEFILE运行Python(或其他)程序来重新生成该“.h”文件
如果,只有当,这是必要的。

关于c - 用预处理器计算奇偶校验位(带引用调用的奇偶校验功能样式),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11294460/

10-10 13:32