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
の 2 つのバージョンが必要であることを意味します。これは保守の問題です。いずれかのバージョンで行われた変更は、他のバージョンでも繰り返さなければなりません。例えば、volatile
volatile
void circbufu8_reset(struct circbuf_u8_st *cb);
void circbufu8_v_reset(struct circbuf_u8_st volatile *cbv);
volatile
それは常に正しいので、すべてのバージョンをそのまま使用できます。volatile
しかし、それはまた、私が避けたい非ケースに対する悲観化を意味します。
したがって、考えられる解決策は、 /nonメンバーでaunion
を宣言し、メンバーが that の型を持つように宣言することです。volatile
volatile
struct
union
union un_dual_volatile_u8 {
uint8_t volatile v;
uint8_t nv;
};
これは、各関数の 2 つのバージョンの問題を解決するのに役立ちます。しかし、それは本当に役に立ちますか?そのような関数にはどのようなセマンティクスがありますか? 私の理解では、コンパイラは に必要な最も厳密なセマンティクスを使用する必要があるため、実際には、これは、同じ悲観化を伴う、union
everything- オプションの不必要に複雑なバージョンになります。volatile
したがって、質問は次のとおりです。
- 組合が助けてくれないというのは正しいですか?
- 関数の重複とペシミゼーションを回避する方法はありますか?
- このような状況で C++ は役に立ちますか? (関数のオーバーロードはセマンティクス
volatile
と非volatile
セマンティクスを尊重しますか?またはジェネリックを使用しますか?)
(コンパイラの出力を見ることは有効な答えではありません。信頼できる標準ベースの正当な理由を探しています)
編集:質問のC++部分は好奇心からだったので、C++タグを削除しました。そしてもちろん、C11 のジェネリックは問題の解決を容易にしますが、目標は C99 でこれを解決することです。