1

Currently I'm working on writing some code that should be easily expandable. To add a new entry the user must add:

  1. The name of the new entry
  2. The size of the new entry

The name is only needed for populating an enum, the size is needed to reserve some space to store the value of it in.

Frankly I'm not really sure this is even possible as I'm effectively asking if preprocessors can properly split/separate symbols and convert it to somewhat boilerplate code.

So, for example, I'd like to add the following entry:

DECLARE_ENTRY(downlinkCounter, sizeof(uint32_t))
DECLARE_ENTRY(uplinkCounter, sizeof(uint32_t))

Or perhaps:

#define ENTRIES downlinkCounter, sizeof(uint32_t), uplinkCounter, sizeof(uint32_t)

Or:

#define NAME_ENTRIES downlinkCounter, uplinkCounter,
#define SIZE_ENTRIES sizeof(uint32_t), sizeof(uint32_t)

(The last option is not preferred, I prefer to pair the name and size closely)

I'd like this to expand to the following in the header file:

typedef enum {
    downlinkCounter,
    uplinkCounter,
} eEntries_t;

And to expand to this in the source file:

typedef struct {
    uint8_t downlinkCounter[sizeof(uint32_t)];
    uint8_t uplinkCounter[sizeof(uint32_t)];
} sEntries_t;

Can I even do this with C preprocessor? Or will I have to type this out?

Thanks for your help!

3
  • 1
    The preprocessor is pretty dumb. You'd be better off doing pre-build processing with a scripting language. Commented Jan 18, 2021 at 14:25
  • Consider using GPP, GNU gawk, etc... to generate the C code you want to have Commented Jan 18, 2021 at 14:29
  • Hrm, so the answer seems no? Commented Jan 18, 2021 at 14:32

1 Answer 1

2

It might be better to run some C code generating script before compiling, so that you get clear and readable code.

Otherwise, you can centralize pre-processor constants with various macro tricks, so called "X macros". They are good for avoiding code repetition, but turn everything hard to read. In this case:

#define ENTRY_LIST(X)                   \
  X(downlinkCounter, sizeof(uint32_t))  \
  X(uplinkCounter,   sizeof(uint32_t))  \

This list can then be called with various macros to generate specific code segments:

#define ENTRY_ENUM(name, dummy) name,
typedef enum {
  ENTRY_LIST(ENTRY_ENUM)
} eEntries_t;

#define ENTRY_STRUCT(name, size) uint8_t name[size];
typedef struct {
  ENTRY_LIST(ENTRY_STRUCT)
} sEntries_t;

Which is pre-processed to:

typedef enum {
  downlinkCounter, 
  uplinkCounter,
} eEntries_t;

typedef struct {
  uint8_t downlinkCounter[sizeof(uint32_t)]; 
  uint8_t uplinkCounter[sizeof(uint32_t)];
} sEntries_t;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.