unionize 32 bit struct with uint32_t and GCC atomic instructions - c

In a multithreaded program that was written I have some performance problems with very high lock contention.
I have solved this issue by having a few flags within an 32 bit unsigned integer.
currently I just bit shift the values in a temporary variable and then atomically write it.
But I don`t really like to remember the exact amount of bit shifts or where exactly what flag resides.
So I have been wondering if I could just make a union with a uint32_t and the struct with my bitflags with the same size, couldn`t I acces the bitflags by the struct and atomically write it as a uint32_t?
below is the code on how I`d like it to work. It does work but I am unsure on whether this is allowed
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
typedef struct atomic_flags {
unsigned int flags1 : 2;
unsigned int flags2 : 2;
unsigned int flags3 : 2;
unsigned int flags4 : 2;
unsigned int flags5 : 8;
unsigned int reserved : 16;
}atomic_flags;
union data {
atomic_flags i;
uint32_t q;
} data;
int main() {
union data test1;
union data test2;
test1.i.flags1 = 1;
test1.i.flags2 = 2;
test1.i.flags3 = 3;
test1.i.flags4 = 2;
test1.i.flags5 = 241;
test1.i.reserved = 1337;
printf("%u\n", test1.q);
__atomic_store_n(&test2.q, test1.q, __ATOMIC_SEQ_CST);
printf("test1 flags1: %u\n", test1.i.flags1);
printf("test1 flags2: %u\n", test1.i.flags2);
printf("test1 flags3: %u\n", test1.i.flags3);
printf("test1 flags4: %u\n", test1.i.flags4);
printf("test1 flags5: %u\n", test1.i.flags5);
printf("test1 reserved: %u\n", test1.i.reserved);
printf("test2 flags1: %u\n", test2.i.flags1);
printf("test2 flags2: %u\n", test2.i.flags2);
printf("test2 flags3: %u\n", test2.i.flags3);
printf("test2 flags4: %u\n", test2.i.flags4);
printf("test2 flags5: %u\n", test2.i.flags5);
printf("test2 reserved: %u\n", test2.i.reserved);
}
or maybe this is even possible?
__atomic_store_n(&test2.i.flags1, 2, __ATOMIC_SEQ_CST);

It is implementation defined.
If you want to make all the masking and shifting easier and to reduce the likelihood of mistakes, then a sturdier (but uglier) way would be enlist the preprocessor to help you out:
/*
* widths of the bitfields; these values can be changed independently of anything
* else, provided that the total number of bits does not exceed 32.
*/
#define FLAG_flag1_BITS 2
#define FLAG_flag2_BITS 2
#define FLAG_flag3_BITS 2
#define FLAG_flag4_BITS 2
#define FLAG_flag5_BITS 8
/* Macro evaluating to the number of bits in the named flag */
#define FLAG_BITS(flagname) (FLAG_ ## flagname ## _BITS)
/*
* Positions of the flags in the overall bitmask; these adapt to the flag widths
* above, but a new macro (with the same pattern) will be needed if a bitfield
* is added.
*/
#define FLAG_flag1_SHIFT 0
#define FLAG_flag2_SHIFT (FLAG_flag1_SHIFT + FLAG_flag1_BITS)
#define FLAG_flag3_SHIFT (FLAG_flag2_SHIFT + FLAG_flag2_BITS)
#define FLAG_flag4_SHIFT (FLAG_flag3_SHIFT + FLAG_flag3_BITS)
#define FLAG_flag5_SHIFT (FLAG_flag4_SHIFT + FLAG_flag4_BITS)
/* Macro evaluating to the position of the named flag in the overall bitfield */
#define FLAG_SHIFT(flagname) (FLAG_ ## flagname ## _SHIFT)
/* evaluates to a bitmask for selecting the named flag's bits from a bitfield */
#define FLAG_MASK(flagname) \
((~(((uint32_t) 0xffffffff) << FLAG_BITS(flagname))) << FLAG_SHIFT(flagname))
/* evaluates to a bitfield having the specified flag set to the specified value */
#define FLAG(flagname, v) ((v << FLAG_SHIFT(flagname)) & FLAG_MASK(flagname))
/* macro to set the specified flag in the specified bitfield to the specified value */
#define SET_FLAG(flagname, i, v) \
do { i = (i & ~FLAG_MASK(flagname)) | FLAG(flagname, v); } while (0)
/* macro to retrieve the value of the specified flag from the specified bitfield */
#define GET_FLAG(flagname, i) (((i) & FLAG_MASK(flagname)) >> FLAG_SHIFT(flagname))
/* usage example */
int function(uint32_t bitfield) {
uint32_t v;
SET_FLAG(flag2, bitfield, 1);
v = GET_FLAG(flag5, bitfield);
}
Though that involves a prodigous stack of macros, it's mostly driven by the first set, that give the bitfield widths. Substantially all of that will compile down to the same shift and mask operations that you would use anyway, as the computations will be performed mostly by the preprocessor and/or compiler. Actual usage is very simple.

Related

Function to generate the corresponding mask for a bit field

I have a 32 bit register R with various bit fields declared as follows:
typedef union {
uint32_t raw;
struct {
uint32_t F1 : 0x4;
uint32_t F2 : 0x8;
uint32_t F3 : 0x8;
uint32_t F4 : 0xC;
}
} reg1
I also have a regWrite macro that read-modify-writes a field in the register as follows:
#define RegWrite(Reg, Field, Addr, Val) do {
Reg.raw = read32(Addr);
Reg.Field = Val;
write32(Addr, Reg.raw);
} while(0)
Now, I wanted to enhance the RegWrite module to optionally output a script to console instead of actually programming hardware, so that this can be saved and re-run at a later point of time.
For example, if I call out to regWrite as follows:
regWrite(reg1, F2, 0x12345678, 0xC)
The print output from the macro should look something like this:
set variable1 [read 32 0x12345678]
set variable1 [ ($variable1 & 0xFFFFF00F) | (0xC << 4) ]
write 32 0x12345678 variable1
How would I generate 0xFFFFF00F, and 4 within the macro? Thanks!
Well, your question lacks some important information, including:
What do you try to achive?
Why do you need to give just the struct member name as an argument?
This might be an X-Y-problem.
Anyway, from the literal requirement:
Fn(X) should print out 0xY, and Z.
You can do this with a macro:
#include <stdint.h>
#include <stdio.h>
struct F {
uint32_t F1 : 0x4;
uint32_t F2 : 0x8;
uint32_t F3 : 0x8;
uint32_t F4 : 0xC;
};
#define Fn(Fx) do { \
union { \
struct F f; \
uint32_t u; \
} v; \
v.u = 0; \
v.u = ~v.u; \
v.f.Fx = 0; \
uint32_t m = v.u; \
int b; \
for (b = 0; (v.u & 1) != 0; b++) { \
v.u >>= 1; \
} \
(void)printf("0x%0X %d\n", m, b); \
} while (0)
int main(void) {
/* Fn(F2) should print out 0xFFFFF00F, and 4. */
Fn(F2);
/* Fn(F3) should print out 0xFFF00FFF, and 12. */
Fn(F3);
return 0;
}
Some notes to this hacked "solution":
It uses do { ... } while(0) to make sure that the macro can't be used as an expression, only as a statement.
There is no interpretation of Fx until it is read by the compiler in the line v.f.Fx = 0.
The code is only for C.
Each time it is used it will take clock cycles, and it needs code space. This seems to be unnecessary for constant expressions.
It works by defining a union that can be used as the struct or the resulting uint32_t.
The mask is generated by setting all bits to 1, and then resetting only the given struct member to 0.
The bit offset is obtained by looking for the first 0-bit from the right.
Please be aware that the standard makes no promisses about the order of bitfields in a memory word ("unit"), not even that they are in the same memory word. For further details see the chapter "Structure and union specifiers" of the version of the standard your compiler complies to.
But if you need the values for other purposes you should think about your architectur, and of course of the possibilities of the C standard. As I said, presumably you're trying to solve a completely other problem. And for this, the shown source is not the solution.
OK, I found some time to search for some more usable solution.
#include <stdint.h>
#include <stdio.h>
struct F {
uint32_t F1 : 0x4;
uint32_t F2 : 0x8;
uint32_t F3 : 0x8;
uint32_t F4 : 0xC;
};
typedef union {
struct F f;
uint32_t u;
} Fn_type;
uint32_t Fn_mask_helper(Fn_type v) {
return ~v.u;
}
#define Fn_mask(Fx) Fn_mask_helper((Fn_type){.u=0, .f.Fx=~0})
int Fn_bit_offset_helper(Fn_type v) {
v.u = ~v.u;
int b;
for (b = 0; (v.u & 1) != 0; b++) {
v.u >>= 1;
}
return b;
}
#define Fn_bit_offset(Fx) Fn_bit_offset_helper((Fn_type){.u=0, .f.Fx=~0})
int main(void) {
uint32_t m2 = Fn_mask(F2);
int b2 = Fn_bit_offset(F2);
(void)printf("0x%0X %d\n", m2, b2);
uint32_t m3 = Fn_mask(F3);
int b3 = Fn_bit_offset(F3);
(void)printf("0x%0X %d\n", m3, b3);
return 0;
}
To access the field (struct member) specified in the argument we need to use a macro. In C we can't use the name of a struct member as an argument on its own. Remember, the C preprocessor knows nothing about C. It is a quite simple search'n'replace tool.
This macro expands to the call to its helper function which takes the union as a parameter. The macro replacement text contains an initialization for this union with all bits on 0 but the bits of the concerned struct member.
The helper functions do the same as the macro in my other answer. In Fn_bit_offset_helper() the inversion of v.u together with the right shift ensures that the loop will not loop forever.
Note: You need a compiler in compliance with at least C99.

left shift count >= width of type in C macro

I have written a C Macro to set/unset Bits in a uint32 variable. Here are the definitions of the macros:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{\
if(x < 0 || x >63){\
break;\
}\
if(((uint32_t)x)<32U){\
(error_field |= ((uint32_t)1U << ((uint32_t)x)));\
break;\
} else if(((uint32_t)x)<64U){\
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));\
}\
}while(0)
#define RESET_ERROR_BIT(x) do{\
if(((uint32_t)x)<32U){\
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));\
break;\
} else if(((uint32_t)x) < 64U){\
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));\
}\
} while(0)
I am passing a field of an enumeration, that looks like this:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
This warning is produced:
left shift count >= width of type [-Wshift-count-overflow]
I am calling the Macros like this:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
I get this warning with every macro, even with those where the left shift count is < 31.
If I use the definition of the macro without the macro, it produces no warning. The behaviour is the same with a 64 bit variable. I am programming a STM32F7 with AC6 STM32 MCU GCC compiler.
I can't figure out why this happens. Can anyone help me?
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{\
if((x)<32U){\
SET_BIT(error_field, x);\
} else if((x)<64U){\
SET_BIT(error_field2, x);\
}\
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
#M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{\
if((x) < 0 || (x) >63){\
break;\
}\
if(((uint32_t)x)<32U){\
(error_field |= ((uint32_t)1U << ( (x)&31 )));\
break;\
} else if(((uint32_t)x)<64U){\
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));\
}\
}while(0)
As a general rule: good to use () around each usage of x.
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
S to set a bit
R to reset a bit
T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (\
((unsigned)(x)>63)?err1=err1:((x)<32)?\
(err1 |= (1U<<(x))):\
(err2 |= (1U<<((x)-32)))\
)
#define RESET_ERROR_BIT(x) (\
((unsigned)(x)>63)?err1=err1:((x)<32)?\
(err1 &= ~(1U<<(x))):\
(err2 &= ~(1U<<((x)-32)))\
)
#define TOGGLE_ERROR_BIT(x) (\
((unsigned)(x)>63)?err1=err1:((x)<32)?\
(err1 ^= (1U<<(x))):\
(err2 ^= (1U<<((x)-32)))\
)
int main(int argc, char *argv[])
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08X\n",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.

fwrite() in c writes bytes in a different order

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = 0xabcdef;
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}
this is my code and when I see the test_output file with xxd it gives following output.
$ xxd -c 12 -g 3 test_output
0000000: efcdab 00 ....
I'm expecting it to print abcdef instead of efcdab.
Which book are you reading? There are a number of issues in this code, casting the return value of malloc for example... Most importantly, consider the cons of using an integer type which might vary in size and representation from system to system.
An int is guaranteed the ability to store values between the range of -32767 and 32767. Your implementation might allow more values, but to be portable and friendly with people using ancient compilers such as Turbo C (there are a lot of them), you shouldn't use int to store values larger than 32767 (0x7fff) such as 0xabcdef. When such out-of-range conversions are performed, the result is implementation-defined; it could involve saturation, wrapping, trap representations or raising a signal corresponding to computational error, for example, the latter of two which could cause undefined behaviour later on.
You need to translate to an agreed-upon field format. When sending data over the write, or writing data to a file to be transferred to other systems, it's important that the protocol for communication be agreed upon. This includes using the same size and representation for integer fields. Both output and input should be followed by a translation function (serialisation and deserialisation, respectively).
Your fields are binary, and so your file should be opened in binary mode. For example, use fopen(..., "wb") rather than "w". In some situations, '\n' characters might be translated to pairs of \r\n characters, otherwise; Windows systems are notorious for this. Can you imagine what kind of havoc and confusion this could wreak? I can, because I've answered a question about this problem.
Perhaps uint32_t might be a better choice, but I'd choose unsigned long as uint32_t isn't guaranteed to exist. On that note, for systems which don't have htonl (which returns uint32_t according to POSIX), that function could be implemented like so:
uint32_t htonl(uint32_t x) {
return (x & 0x000000ff) << 24
| (x & 0x0000ff00) << 8
| (x & 0x00ff0000) >> 8
| (x & 0xff000000) >> 24;
}
As an example inspired by the above htonl function, consider these macros:
typedef unsigned long ulong;
#define serialised_long(x) serialised_ulong((ulong) x)
#define serialised_ulong(x) (x & 0xFF000000) / 0x1000000 \
, (x & 0xFF0000) / 0x10000 \
, (x & 0xFF00) / 0x100 \
, (x & 0xFF)
typedef unsigned char uchar;
#define deserialised_long(x) (x[3] <= 0x7f \
? deserialised_ulong(x) \
: -(long)deserialised_ulong((uchar[]) { 0x100 - x[0] \
, 0xFF - x[1] \
, 0xFF - x[2] \
, 0xFF - x[3] })
#define deserialised_ulong(x) ( x[0] * 0x1000000UL \
+ x[1] * 0x10000UL \
+ x[2] * 0x100UL \
+ x[3] )
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *f = fopen("test_output", "wb+");
if (f == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
ulong value = 0xABCDEF;
unsigned char datagram[] = { serialised_ulong(value) };
fwrite(datagram, sizeof datagram, 1, f);
printf("%08lX serialised to %02X%02X%02X%02X\n", value, datagram[0], datagram[1], datagram[2], datagram[3]);
rewind(f);
fread(datagram, sizeof datagram, 1, f);
value = deserialised_ulong(datagram);
printf("%02X%02X%02X%02X deserialised to %08lX\n", datagram[0], datagram[1], datagram[2], datagram[3], value);
fclose(f);
return 0;
}
Use htonl()
It converts from whatever the host-byte-order is (endianness of your machine) to network byte order. So whatever machine you're running on you will get the the same byte order. These calls are used so that regardless of the host you're running on the bytes are sent over the network in the right order, but it works for you too.
See the man pages of htonl and byteorder. There are various conversion functions available, also for different integer sizes, 16-bit, 32-bit, 64-bit ...
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main(void) {
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL) {
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = htonl(0xabcdef); // <====== This ensures correct byte order
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}

c macro for setting bits

I have a program that compares variables from two structs and sets a bit accordingly for a bitmap variable. I have to compare each variables of the struct. No. of variables in reality are more for each struct but for simplicity I took 3. I wanted to know if i can create a macro for comparing the variables and setting the bit in the bitmap accordingly.
#include<stdio.h>
struct num
{
int a;
int b;
int c;
};
struct num1
{
int d;
int e;
int f;
};
enum type
{
val1 = 0,
val2 = 1,
val3 = 2,
};
int main()
{
struct num obj1;
struct num1 obj2;
int bitmap = 0;
if( obj1.a != obj2.d)
{
bitmap = bitmap | val1;
}
if (obj1.b != obj2.e)
bitmap = bitmap | val2;
printf("bitmap - %d",bitmap);
return 1;
}
can i declare a macro like...
#define CHECK(cond)
if (!(cond))
printf(" failed check at %x: %s",__LINE__, #cond);
//set the bit accordingly
#undef CHECK
With a modicum of care, you can do it fairly easily. You just need to identify what you're comparing and setting carefully, and pass them as macro parameters. Example usage:
CHECK(obj1.a, obj2.d, bitmap, val1);
CHECK(obj1.b, obj2.e, bitmap, val2);
This assumes that CHECK is defined something like:
#define STRINGIFY(expr) #expr
#define CHECK(v1, v2, bitmap, bit) do \
{ if ((v1) != (v2)) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(v1 != v2)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
You can lay the macro out however you like, of course; I'm not entirely happy with that, but it isn't too awful.
Demo Code
Compilation and test run:
$ gcc -Wall -Wextra -g -O3 -std=c99 xx.c -o xx && ./xx
failed check at 40: obj1.a != obj2.d
failed check at 42: obj1.c != obj2.f
bitmap - 5
$
Actual code:
#include <stdio.h>
struct num
{
int a;
int b;
int c;
};
struct num1
{
int d;
int e;
int f;
};
enum type
{
val1 = 0,
val2 = 1,
val3 = 2,
};
#define STRINGIFY(expr) #expr
#define CHECK(v1, v2, bitmap, bit) do \
{ if ((v1) != (v2)) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(v1 != v2)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
int main(void)
{
struct num obj1 = { 1, 2, 3 };
struct num1 obj2 = { 2, 2, 4 };
int bitmap = 0;
CHECK(obj1.a, obj2.d, bitmap, val1);
CHECK(obj1.b, obj2.e, bitmap, val2);
CHECK(obj1.c, obj2.f, bitmap, val3);
printf("bitmap - %X\n", bitmap);
return 0;
}
Clearly, this code relies on you matching the right elements and bit numbers in the invocations of the CHECK macro.
It's possible to devise more complex schemes using offsetof() etc and initialized arrays describing the data structures, etc, but you'd end up with a more complex system and little benefit. In particular, the invocations can't reduce the parameter count much. You could assume 'bitmap' is the variable. You need to identify the two objects, so you'll specify 'obj1' and 'obj2'. Somewhere along the line, you need to identify which fields are being compared and the bit to set. That could be some single value (maybe the bit number), but you've still got 3 arguments (CHECK(obj1, obj2, valN) and the assumption about bitmap) or 4 arguments (CHECK(obj1, obj2, bitmap, valN) without the assumption about bitmap), but a lot of background complexity and probably a greater chance of getting it wrong. If you can tinker with the code so that you have a single type instead of two types, etc, then you can make life easier with the hypothetical system, but it is still simpler to handle things the way shown in the working code, I think.
I concur with gbulmer that I probably wouldn't do things this way, but you did state that you had reduced the sizes of the structures dramatically (for which, thanks!) and it would become more enticing as the number of fields increases (but I'd only write out the comparisons for one pair of structure types once, in a single function).
You could also revise the macro to:
#define CHECK(cond, bitmap, bit) do \
{ if (cond) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(cond)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
CHECK(obj1.a != obj2.d, bitmap, val1);
...
CHECK((strcmp(obj3.str1, obj4.str) != 0), bitmap, val6);
where the last line shows that this would allow you to choose arbitrary comparisons, even if they contain commas. Note the extra set of parentheses surrounding the call to strcmp()!
You should be able to do that except you need to use backslash for multi-line macros
#ifndef CHECK
#define CHECK(cond) \
if (!(cond)) { \
printf(" failed check at %x: %s",__LINE__, #cond); \
//set the bit accordingly
}
#endif /* CHECK */
If you want to get really fancy (and terse), you can use the concatenation operator. I also recommend changing your structures around a little bit to have different naming conventions, though without knowing what you're trying to do with it, it's hard to say. I also noticed in your bit field that you have one value that's 0; that won't tell you much when you try to look at that bit value. If you OR 0 into anything, it remains unchanged. Anyway, here's your program slightly re-written:
struct num {
int x1; // formerly a/d
int x2; // formerly b/e
int x3; // formerly c/f
};
enum type {
val1 = 1, // formerly 0
val2 = 2, // formerly 1
val3 = 4, // formerly 2
};
// CHECK uses the catenation operator (##) to construct obj1.x1, obj1.x2, etc.
#define CHECK(__num) {\
if( obj1.x##__num != obj2.x##__num )\
bitmap |= val##__num;\
}
void main( int argc, char** argv ) {
struct num obj1;
struct num obj2;
int bitmap = 0;
CHECK(1);
CHECK(2);
CHECK(3);
}
As a reasonable rule of thumb, when trying to do bit-arrays is C, there needs to be a number that can be used to index the bit.
You can either pass that bit number into the macro, or try to derive it.
Pretty much the only thing available at compile time or run time is the address of a field.
So you could use that.
There are a few questions to understand if it might work.
For your structs:
Are all the fields in the same order? I.e. you can compare c with f, and not c with e?
Do all of the corresponding fields have the same type
Is the condition just equality? Each macro will have the condition wired in, so each condition needs a new macro.
If the answer to all is yes, then you could use the address:
#define CHECK(s1, f1, s2, f2) do \
{ if ((&s1.f1-&s1 != &s2.f2-&s2) || (sizeof(s1.f1)!=sizeof(s2.f2)) \
|| (s1.f1) != (s2.f2) \
{ printf("failed check at %d: ", #s1 "." #f1 "!=" #s1 "." #f1 "\n", \
__LINE__); \
(shared_bitmap) |= (1 << (&s1.f1-&s1)); // test failed \
} \
} while (0)
I'm not too clear on whether it is a bitmap for all comparisons, or one per struct pair. I've assumed it is a bit map for all.
There is quite a lot of checking to ensure you haven't broken 'the two rules':
(&s1.f1-&s1 != &s2.f2-&s2) || (sizeof(s1.f1)!=sizeof(s2.f2))
If you are confident that the tests will be correct, without those constraints, just throw that part of the test away.
WARNING I have not compiled that code.
This becomes much simpler if the values are an array.
I probably wouldn't use it. It seems a bit too tricky to me :-)

request for comments on original crc32 checksum

Can someone explain to me why the crc is inverted twice ?
/* ========================================================================
* Table of CRC-32's of all single-byte values (made by make_crc_table)
*/// definicao de uint e uchar
#include <stdio.h>
//#define TEST 1
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ushort
#define ushort unsigned short
#endif
static const uint crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
/* =========================================================================
* This function can be used by asm versions of crc32()
*/
const uint * get_crc_table()
{
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty) make_crc_table();
#endif
return (const uint *)crc_table;
}
/* ========================================================================= */
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
/* ========================================================================= */
uint crc32(
uint crc,
const uchar *buf,
uint len)
{
if (buf == NULL) return 0L;
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();
#endif
crc = crc ^ 0xffffffffL;
while (len >= 8)
{
DO8(buf);
len -= 8;
}
if (len) do {
DO1(buf);
} while (--len);
return crc ^ 0xffffffffL;
}
#ifdef TEST
int main()
{
printf("Testando crc \n");
printf("%0.8x \n ", crc32(0,"ala", 1));
}
#endif
If you're interested in CRC checksums then this is a must-read:
http://www.ross.net/crc/download/crc_v3.txt
Though it has been a long time since I've read it, so I'm not sure it will answer your specific question.
Edit: At least it contains the parameterization.
Here is the specification for the CRC-32 algorithm which is reportedly
used in PKZip, AUTODIN II, Ethernet, and FDDI.
Name : "CRC-32"
Width : 32
Poly : 04C11DB7
Init : FFFFFFFF
RefIn : True
RefOut : True
XorOut : FFFFFFFF
Check : CBF43926
The first inversion is done because otherwise, adding leading zero bits to the buffer would not change the resulting CRC value (assuming the initial CRC value is zero).
I believe the inversion at the end is done so that this function can be called incrementally: Instead of having to call it on the entire data at once, you can call it in blocks, and the two inversions will cancel each other out on adjacent blocks.
Note that these inversions are not done on all CRC32 implementations.

Resources