Use Macro define for declaring multiple version structure in C

Viewed 219

I'm trying to solve a problem about a protocol which has multiple version. Its structure version will continually extend, like the following snippet, the 1.1.2 version may come.

Original:

#include <stdio.h>
#include <stdint.h>

typedef struct GetReading {
    uint8_t val;
} GetReading_T;


int main()
{
    GetReading_T instaince = {0};
    instaince.val = 0x12c;
    
    printf("%02x\n", instaince.val);

    return 0;
}

After:

#include <stdio.h>
#include <stdint.h>

#define MULTI_S(NAME, VERSION) \
typedef struct NAME##_##VERSION { 
    
#define MULTI_E(NAME, VERSION) \
} NAME##_##VERSION##_t; 

MULTI_S(GetReading, 1_1_0)
    uint8_t val;
MULTI_E(GetReading, 1_1_0)

MULTI_S(GetReading, 1_1_1)
    uint16_t val;
MULTI_E(GetReading, 1_1_1)

/*
typedef struct GetReading_1_1_0 {
    uint8_t val;
} GetReading_1_1_0_t;
typedef struct GetReading_1_1_1 {
    uint16_t val;
} GetReading_1_1_1_t;
*/

typedef union GetReading {
    GetReading_1_1_0_t v110;
    GetReading_1_1_1_t v111;
} GetReading_T;


int main()
{
    GetReading_T instaince = {0};
    instaince.v111.val = 0x12c;

    int type = 1;
    if(type == 1) {
        printf("%04x\n", instaince.v111.val);
    } else if (type == 2) {
        printf("%02x\n", instaince.v110.val); 
    }

    return 0;
}

I just wonder if this macro technic is too hard to read and maybe redundant because it can achieve the same by declaring directly. And I found it difficult to warp the macro with the current implementation.

Is there any better practice to solve this kind of problem by C/C++?

2 Answers

Consider using the macro only to generate a name for the structure. Moreover you can leave the structures untagged because there is alias for them. It would be easier to parse by a human.


#define MULTI(NAME, VERSION) NAME##_##VERSION##_t

typedef struct {
  uint8_t val;
} MULTI(GetReading, 1_1_0);

typedef struct {
  uint16_t val;
} MULTI(GetReading, 1_1_1);

typedef union GetReading {
   MULTI(GetReading, 1_1_0) v110;
   MULTI(GetReading, 1_1_1) v111;
} GetReading_T;

Is there any better practice to solve this kind of problem by C/C++?

I strongly recommend using code generation instead of C macros or C++ templates.

Use a script or program to generate the different versions of your protocol. It will be cleaner, easier to understand, faster to compile and easier to maintain.

You can even commit the generated headers so that you only pay the generating price once!

Related