Question

I would like to define a macro that will help me to auto generate offsets. Something like this:

#define MEM_OFFSET(name, size) ...

MEM_OFFSET(param1, 1);
MEM_OFFSET(param2, 2);
MEM_OFFSET(param3, 4);
MEM_OFFSET(param4, 1);

should generate the following code:

const int param1_offset = 0;
const int param2_offset = 1;
const int param3_offset = 3;
const int param4_offset = 7;

or

enum {
  param1_offset = 0,
  param2_offset = 1,
  param3_offset = 3,
  param4_offset = 7,
}

or even (not possible using C-preprocessor only for sure, but who knows ;)

#define param1_offset 0
#define param2_offset 1
#define param3_offset 3
#define param4_offset 7

Is it possible to do without running external awk/bash/... scripts?

I'm using Keil C51

Was it helpful?

Solution 2

In the comments to your post you mention that you're managing an EEPROM memory map, so this answer relates to managing memory offsets rather than answering your specific question.

One way to manage EEPROM memory is with the use of a packed struct. ie, one where there is no space between each of the elements. The struct is never instantiated, it is only used for offset calculations.

typedef struct {
    uint8_t param1;
#ifdef FEATURE_ENABLED
    uint16_t param2;
#endif
    uint8_t param3;
} __packed eeprom_memory_layout_t;

You could then use code like the following to determine the offset of each element as needed(untested). This uses the offsetof stddef macro.

uint16_t read_param3(void) {
    uint8_t buf;
    eeprom_memory_layout_t * ee;

    /* eeprom_read(offset, size, buf) */
    eeprom_read(offsetof(eeprom_memory_layout_t, param3), sizeof(ee->param3), &buf);

    return buf;
}

Note that the struct is never instantiated. Using a struct like this makes it easy to see your memory map at a glance, and macros can easily be used to abstract away the calls to offsetof and sizeof during access.

OTHER TIPS

It seems I've found a solution with enum:

#define MEM_OFFSET(name, size) \
    name ## _offset, \
    ___tmp__ ## name = name ## _offset + size - 1, // allocate right bound offset and introduce a gap to force compiler to use next available offset

enum {
 MEM_OFFSET(param1, 1)
 MEM_OFFSET(param2, 2)
 MEM_OFFSET(param3, 4)
 MEM_OFFSET(param4, 1)
};

If you want to create several structures based on some preprocessor declarations, you could do something like:

#define OFFSET_FOREACH(MODIFIER)    \
    MODIFIER(1)                     \
    MODIFIER(2)                     \
    MODIFIER(3)                     \
    MODIFIER(4)

#define OFFSET_MODIFIER_ENUM(NUM) param##NUM##_offset,
enum 
{
    OFFSET_FOREACH(OFFSET_MODIFIER_ENUM)
};

The preprocessor would then produce the following code:

enum
{
    param1_offset,
    param2_offset,
    param3_offset,
    param4_offset,
}

I'm sure somebody will figure a nice preprocessor trick to compute the offset values with the sum of its predecessors :)

If you are doing this in C code, you have to keep in mind that const int declarations do not declare constants in C. To declare a named constant you have to use either enum or #define.

If you need int constants specifically, then enum will work well, although I the auto-generation part might be tricky in any case. Off the top of my head I can only come up with something as ugly as

#define MEM_OFFSET_BEGIN(name, size)\
  enum {\
    name##_OFFSET = 0,\
    name##_SIZE__ = size,

#define MEM_OFFSET(name, size, prev_name)\
  name##_OFFSET = prev_name##_OFFSET + prev_name##_SIZE__,\
  name##_SIZE__ = size,

#define MEM_OFFSET_END()\
  };

and then

MEM_OFFSET_BEGIN(param1, 1)
MEM_OFFSET(param2, 2, param1)
MEM_OFFSET(param3, 4, param2)
MEM_OFFSET(param4, 1, param3)
MEM_OFFSET_END()

Needless to say, the fact that it requires the next offset declaration to refer to the previous offset declaration by name defeats most of the purpose of this construct.

Try something like:

#define OFFSET(x) offsetof(struct {\
char param1[1], param2[2], param3[4], param4[1];\
},x)

Then you can use OFFSET(param1), etc. and it's even an integer constant expression.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top