我正在使用 GCC 在 C99 上为嵌入式环境开发。我做了一个小库来处理循环缓冲区和队列。它实现并处理包含缓冲区和所需元数据的基本结构的实例。
struct circbuf_u8_st {
const uint8_t buffer_num_elems;
uint8_t head;
uint8_t tail;
uint8_t * buffer;
};
有时它struct
被用作volatile
全局,因为它用于生成数据的中断例程和消耗数据的主循环之间的通信。
但有时它struct
被用作非volatile
本地的,例如当主循环的一部分生成数据以供稍后在同一个主循环上使用时。
有时struct
有时volatile
不存在意味着任何处理该参数的函数都struct
需要两个版本,用于参数volatile
和非volatile
参数。这是一个维护问题:在一个版本中所做的任何更改都必须在另一个版本中重复。例如,
void circbufu8_reset(struct circbuf_u8_st *cb);
void circbufu8_v_reset(struct circbuf_u8_st volatile *cbv);
我可以选择volatile
一切的版本,因为那总是正确的。但这也意味着对volatile
我想避免的非案例的悲观。
因此,一种可能的解决方案是声明 a union
with volatile
/nonvolatile
成员,并将struct
成员声明为具有 that 的类型union
。
union un_dual_volatile_u8 {
uint8_t volatile v;
uint8_t nv;
};
这将有助于摆脱每个功能的 2 个版本问题。但是,真的有用吗?这样的功能将(可能)具有什么语义?我的理解是编译器必须使用 . 所需的最严格的语义union
,所以实际上这只是volatile
all-option 的一个不必要的复杂版本,具有相同的悲观化。
所以,问题是:
- 我说工会不帮忙是对的吗?
- 那么有什么办法可以避免功能重复和悲观化呢?
- C++ 在这种情况下会有所帮助吗?(函数重载会尊重
volatile
和非volatile
语义吗?或者可能使用泛型?)
(查看编译器输出不是一个有效的答案;我正在寻找可以依赖的基于标准的理由)
编辑:我删除了 C++ 标签,因为问题的 C++ 部分更多是出于好奇。当然 C11 的泛型使问题更容易解决,但目标是在 C99 中解决这个问题。