2

Consider I want to generate parities at compile time. The parity calculation is given literal constants and with any decent optimizer it will boil down to a single constant itself. Now look at the following parity calculation with the C preprocessor:

#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));

This will calculate the parity at compile time, but it will produce an enormous amount of intermediate code, expanding to 16 instances of the expression u16 which itself can be e.g. an arbitrary complex expression. The problem is that the C preprocessor can't evaluate intermediary expressions and in the general case only expands text (you can force it to do integer arithmetic in-situ but only for trivial cases, or with gigabytes of #defines). I have found that the parity for 3 bits can be generated at once by an arithmetic expression: ([0..7]*3+1)/4. This reduces the 16-bit parity to the following macro:

#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))

which expands u16only 6 times. Is there an even cheaper (in terms of number of expansions) way, e.g. a direct formula for a 4,5,etc. bit parity? I couldn't find a solution for a linear expression of the form (x*k+d)/m for acceptable (non-overflowing) values k,d,m for a range > 3 bits. Anyone out there with a more clever shortcut for preprocessor parity calculation?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
slartibartfast
  • 641
  • 4
  • 12
  • 1
    Don't use macros, use inline functions. That provides the intermediate expression evaluation you are looking for. – mfontanini Jul 02 '12 at 13:17
  • 1
    I have to agree with mfontanini that it would be better to avoid macros here. If you are using c++11 you can use a `constexpr` method. If you don't use c++11 and need the result to be a compiletime constant (not just likely to be evaluated at compiletime, but usable as a constant) use template metaprogramming to evaluate that at compiletime, otherwise just use an inline function. If you use plain C, you might want to remove C++ from the tags. – Grizzly Jul 02 '12 at 13:22
  • Sorry that I tagged it with C++ also, didn't want to exclude them V8-autodrive-endless-horsepower guys ;). Alas, this should execute in a pure C89 environnment – slartibartfast Jul 02 '12 at 13:26
  • 1
    C and C++ are different languages. If you require an answer that only works on C, you shouldn't tag it C++. – mfontanini Jul 02 '12 at 14:00
  • 1
    You don't need that many &'s. You can use this instead: `#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)`. – Alexey Frunze Jul 02 '12 at 19:32

2 Answers2

1

Is something like this what you are looking for? The following "PARITY16(u16)" preprocessor macro can be used as a literal constant in structure assignments, and it only evaluates the argument once.

/* 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 : */

Much like the original code you posted, it pairs up bits and (in effect) calculates the XOR between each pair, then from the results it pairs up the bits again, halving the number of bits each time until only a single parity bit remains.

But is that really what you wanted ?

Many people say they are calculating "the parity" of a message. But in my experience, most of the time they are really generating a error-detection code bigger than a single parity bit -- a LRC, or a CRC, or a Hamming code, or etc.

further details

If the current system is compiling in a reasonable amount of time, and it's giving the correct answers, I would leave it alone. Refactoring "how the pre-processor generates some constant" will produce bit-for-bit identically the same runtime executable. I'd rather have easy-to-read source even if it takes a full second longer to compile.

Many people use a language easier-to-read than the standard C preprocessor to generate C source code. See pycrc, the character set extractor, "using Python to generate C", etc.

If the current system is taking way too long to compile, rather than tweak the C preprocessor, I would be tempted to put that message, including the parity, in a separate ".h" file with hard-coded constants (rather than force the C pre-processor to calculate them every time), and "#include" that ".h" file in the ".c" file for the embedded system.

Then I would make a completely separate program (perhaps in C or Python) that does the parity calculations and prints out the contents of that ".h" file as pre-calculated C source code, something like

print("int message[] = { 0x%x, 0x%x, 0x%x };\n",
    M[0], M[1], parity( M[0]^M[1] ) );

and tweak my MAKEFILE to run that Python (or whatever) program to regenerate that ".h" file if, and only if, it is necessary.

Community
  • 1
  • 1
David Cary
  • 5,250
  • 6
  • 53
  • 66
  • Thanks for the elaborate answer and your additional thoughts. I completely agree with you, but there had been just reasons why I resorted to pure C preprocessing: the code went into an existing project with quite strict config management, so the introduction of an external code generation language wasn't an option. BTW: my arithmetic shortcut can also be rolled out to more bits in parallel: #define PARITY_24(x) \ ((((((((x)&070707070u)*3+010101010)&040404040) + \ ((((x)&007070707u)*3+001010101)&004040404)) * 0111111110) / 0400000000) & 1) – slartibartfast May 27 '13 at 12:17
-1

As mfontanini says, an inline function is much better.

If you insist on a macro, you can define a temporary variable.
With gcc, you can do it and still have the macro which behaves as an expression:
#define PARITY(x) ({int tmp=x; PARITY16(tmp);})
If you want to stick to the standard, you have to make the macro a statement:
#define PARITY(x, target) do { int tmp=x; target=PARITY16(tmp); } while(0).

In both cases, you can have ugly bugs if tmp ends up a name used in the function (even worse - used within the parameter passed to the macro).

ugoren
  • 16,023
  • 3
  • 35
  • 65
  • 1
    Sorry but you missed my main requirement: the parity must evaluate at compile time. – slartibartfast Jul 02 '12 at 19:01
  • Why did I miss it? Macros (and inline functions) whose parameters are constant evaluate at compile time. – ugoren Jul 03 '12 at 06:55
  • 1
    To be more specific, I would like it to evaluate to a literal constant to be able to use it in "int message[] = { 0x1234, 0x5678, PARITY16(0x1234^0x5678));" – slartibartfast Jul 03 '12 at 14:31
  • If `message` is inside a function, there's no problem. But outside a functions, my suggestions indeed don't work. – ugoren Jul 04 '12 at 06:38