1. ホーム
  2. c++

[解決済み] C++のクラスメモリ構造で「スペーサー」を作成するにはどうしたらいいですか?

2023-02-16 09:42:06

質問

問題

低レベルのベアメタル組み込み コンテキストで、私は、C++ 構造内に、名前のない空白のスペースをメモリ内に作成し、ユーザーがそのメモリ位置にアクセスするのを禁止したいと思います。

今現在、私は醜い uint32_t :96; というビットフィールドを置くことで実現しました。これは都合よく3つの単語の代わりになりますが、GCCから警告(Bitfield too large to fit in uint32_t)を出します。

問題なく動作しますが、数百ものこれらの警告があるライブラリを配布したい場合、あまりきれいではありません...。

どうすれば適切にできるのでしょうか?

そもそも、なぜ問題が発生するのでしょうか?

私が取り組んでいるプロジェクトは、マイクロコントローラ (STMicroelectronics STM32) 全体のさまざまな周辺機器のメモリ構造を定義することで構成されています。これを行うには、ターゲットとなるマイクロコントローラーに応じて、すべてのレジスタを定義する複数の構造体のユニオンを含むクラスが必要となります。

かなり単純なペリフェラルの例として、汎用入出力(GPIO)があります。

union
{

    struct
    {
        GPIO_MAP0_MODER;
        GPIO_MAP0_OTYPER;
        GPIO_MAP0_OSPEEDR;
        GPIO_MAP0_PUPDR;
        GPIO_MAP0_IDR;
        GPIO_MAP0_ODR;
        GPIO_MAP0_BSRR;
        GPIO_MAP0_LCKR;
        GPIO_MAP0_AFR;
        GPIO_MAP0_BRR;
        GPIO_MAP0_ASCR;
    };
    struct
    {
        GPIO_MAP1_CRL;
        GPIO_MAP1_CRH;
        GPIO_MAP1_IDR;
        GPIO_MAP1_ODR;
        GPIO_MAP1_BSRR;
        GPIO_MAP1_BRR;
        GPIO_MAP1_LCKR;
        uint32_t :32;
        GPIO_MAP1_AFRL;
        GPIO_MAP1_AFRH;
        uint32_t :64;
    };
    struct
    {
        uint32_t :192;
        GPIO_MAP2_BSRRL;
        GPIO_MAP2_BSRRH;
        uint32_t :160;
    };
};

ここで、すべての GPIO_MAPx_YYY はマクロで、次のように定義されます。 uint32_t :32 またはレジスタタイプ(専用の構造体)として定義されます。

ここでは uint32_t :192; であり、うまく動作しますが、警告が発生します。

これまで検討したこと

に置き換えたかもしれませんが、いくつかの uint32_t :32; (ここでは6個)に置き換えているかもしれませんが、極端な話、私の場合は uint32_t :1344; (42)のようなものもあります(中略)。だから、構造体生成がスクリプト化されているとはいえ、他の8k行の上に100行程度を追加するのは避けたい。

正確な警告メッセージは以下のようなものです。 width of 'sool::ll::GPIO::<anonymous union>::<anonymous struct>::<anonymous>' exceeds its type (いかにも怪しげな感じが好きです)。

私はむしろ ではなく の使用は、単に警告を削除することでこれを解決することができます。

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-WTheRightFlag"
/* My code */
#pragma GCC diagnostic pop

が解決策になるかもしれません...もし私が TheRightFlag . しかし、指摘されているように このスレッド , gcc/cp/class.c この悲しいコード部分と

warning_at (DECL_SOURCE_LOCATION (field), 0,
        "width of %qD exceeds its type", field);

がないことを物語っています。 -Wxxx フラグがないことがわかります。

どのように解決するのですか?

複数の隣接する匿名ビットフィールドを使用します。 そのため、代わりに

    uint32_t :160;

といった具合に、例えば

    uint32_t :32;
    uint32_t :32;
    uint32_t :32;
    uint32_t :32;
    uint32_t :32;

匿名にしたいレジスタごとに1つずつ。

埋めるべき大きなスペースがある場合、単一の32ビットスペースを繰り返すためにマクロを使用することが明確であり、エラーが発生しにくいかもしれません。 例えば、与えられた

#define REPEAT_2(a) a a
#define REPEAT_4(a) REPEAT_2(a) REPEAT_2(a)
#define REPEAT_8(a) REPEAT_4(a) REPEAT_4(a)
#define REPEAT_16(a) REPEAT_8(a) REPEAT_8(a)
#define REPEAT_32(a) REPEAT_16(a) REPEAT_16(a)

すると、1344(42×32bit)のスペースがこうして追加されます。

struct
{
    ...
    REPEAT_32(uint32_t :32;) 
    REPEAT_8(uint32_t :32;) 
    REPEAT_2(uint32_t :32;)
    ...
};