选择结构成员并改变其内容的函数

时间:2018-03-27 17:25:07

标签: c

所以我试着编写一个函数,它接受一个结构的指针,一个结构的元素(表示一个寄存器)和一个int,它代表我们想要设置的寄存器中的位

我的想法是

SET_GPIO_BIT(GPIO_TypeDef *PORT, volatile uint32_t reg, uint32_t bit) {
    PORT->reg |= (1 << bit);
}

我的头文件中的结构看起来像

typedef struct {
    volatile uint32_t    MODER;
    volatile uint32_t    OTYPER;
    //insert more registers here
    volatile uint32_t    BSRR;
} GPIO_TypeDef;

然后我得到一个(arm-none-eabi-gcc)编译器错误:

error: 'GPIO_TypeDef {aka struct <anonymous>}' has no member named 'reg'

基本思想是我希望能够写出像

这样的东西
SET_GPIO_BIT(GPIOA, BSRR, 7);

将选择GPIO端口A并将BSRR寄存器中的第7位置1(例如)。有没有办法做这样的事情?

2 个答案:

答案 0 :(得分:2)

由于你要找的是文本替换,你需要一个宏:

#define SET_GPIO_BIT(port, reg, bit) ((port)->reg |= (1 << (bit)))

或者,由于所有寄存器的类型相同,您可以改为使用函数并根据具体情况传入相关寄存器的地址:

void SET_GPIO_BIT(volatile uint32_t *reg, uint32_t bit) {
    *reg |= (1 << bit);
}

然后你会这样称呼:

if (set_MODER) {
    SET_GPIO_BIT(&GPIOA->MODER, 7);
} else if (set_OTYPER) {
    SET_GPIO_BIT(&GPIOA->OTYPER, 7);
...

答案 1 :(得分:0)

这不是对所述问题的回答;它是以不同方式解决潜在问题的建议。

不是将“寄存器”作为结构中单独命名的成员,而是使用数组:

enum {
    IOREG_MODE = 0,
    IOREG_OTYPE,
    /* All registers, in order */
    IOREG_COUNT
};

typedef struct {
    volatile uint32_t  ioreg[IOREG_COUNT];
} ioregs;

这可以让你使用宏

#define IOREG_SET(port, reg, bit) (((port)->ioreg[reg]) |= (1u << (bit)))
#define IOREG_UNSET(port, reg, bit) (((port)->ioreg[reg]) &= ~(1u << (bit)))
#define IOREG_TOGGLE(port, reg, bit) (((port)->ioreg[reg]) ^= (1u << (bit)))

或静态内联函数,

static inline uint32_t ioreg_set(regs *const port,
                                 const int reg,
                                 const unsigned char bit)
{
    return port->ioreg[reg] |= 1u << bit;
}

static inline uint32_t ioreg_unset(regs *const port,
                                   const int reg,
                                   const unsigned char bit)
{
    return port->ioreg[reg] &= ~(1u << bit);
}

static inline uint32_t ioreg_toggle(regs *const port,
                                    const int reg,
                                    const unsigned char bit)
{
    return port->ioreg[reg] ^= 1u << bit;
}

在任何现代C编译器上,两者都同样快,但static inline函数提供编译时类型检查,并且更容易调试输出错误数据的情况(例如,通过复制写入到调试文本流)。

(如果您的I / O寄存器也支持8位和/或16位访问,则可以使结构成为数组的并集,具有不同的静态内联访问器,具体取决于寄存器的大小。)