通过C预处理器定义偏移的最佳方法

时间:2013-01-15 23:06:32

标签: c c-preprocessor keil

我想定义一个可以帮助我自动生成偏移的宏。像这样:

#define MEM_OFFSET(name, size) ...

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

应生成以下代码:

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

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

甚至(不可能只使用C预处理器,但谁知道;)

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

是否可以不运行外部awk / bash / ...脚本?

我正在使用Keil C51

5 个答案:

答案 0 :(得分:4)

我似乎找到了一个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)
};

答案 1 :(得分:2)

在您对帖子的评论中,您提到您正在管理EEPROM内存映射,因此这个答案与管理内存偏移有关,而不是回答您的具体问题。

管理EEPROM内存的一种方法是使用压缩结构。即,每个元素之间没有空间的那个。结构体永远不会被实例化,它只用于偏移计算。

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

然后,您可以使用以下代码来根据需要确定每个元素的偏移量(未经测试)。这使用offsetof stddef宏。

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;
}

请注意,结构体永远不会被实例化。使用这样的结构可以让您轻松查看内存映射,并且可以轻松地使用宏来抽取访问期间offsetofsizeof的调用。

答案 2 :(得分:0)

如果要基于某些预处理器声明创建多个结构,可以执行以下操作:

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

然后预处理器将生成以下代码:

enum
{
    param1_offset,
    param2_offset,
    param3_offset,
    param4_offset,
}

我确信有人会想出一个很好的预处理技巧来计算偏移值及其前身的总和:)

答案 3 :(得分:0)

如果您在C代码中执行此操作,则必须记住const int声明不在C中声明常量。要声明命名常量,您必须使用{ {1}}或enum

如果你需要专门的#define常量,那么int将会运行良好,尽管我自动生成部分在任何情况下都可能很棘手。在我的脑海中,我只能想出一些丑陋的东西

enum

然后

#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()\
  };

毋庸置疑,它需要下一个偏移声明来引用前一个偏移声明的名称,这违背了这个结构的大部分目的。

答案 4 :(得分:0)

尝试类似:

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

然后你可以使用OFFSET(param1)等,它甚至是一个整数常量表达式。