4

組み込みの世界では、固定長のバッファを介して渡されるデータ構造がよくあります。これらは、次のようなものを使用して比較的簡単に処理できます。

#define TOTAL_BUFFER_LENGTH 4096
struct overlay {
    uint16_t field1;
    uint16_t field2;
    uint8_t  array1[ARY1_LEN];
};
static_assert(sizeof(struct overlay) <= TOTAL_BUFFER_LENGTH);

struct overlay* overlay = malloc(TOTAL_BUFFER_LENGTH);

つまり、データ構造をオーバーレイとして使用して、現在使用されているバッファーの部分に簡単にアクセスできるようにします。

ただし、バッファの最後の数バイトを使用してチェックサムなどを保存するバッファ形式もいくつかあります。現在、次のような構造を使用しています。

struct overlay {
    uint16_t field1;
    uint16_t field2;
    uint8_t  array1[ARY1_LEN];
    char     reserved[TOTAL_BUFFER_LENGTH -
                      sizeof(uint16_t) - sizeof(uint16_t) -
                      (sizeof(uint8_t) * ARY1_LEN) -
                      sizeof(uint32_t)];
    uint32_t crc;
};

これは単純なデータ構造のように見えますが、構造が数十のフィールドを持つように成長すると、絶対的な怪物になります。また、構造体フィールドを追加または削除すると、サイズの計算reservedも同時に更新する必要があるため、保守性の悪夢でもあります。

構造体の最後に項目が 1 つしかない場合 (チェックサムなど)、値の読み取り/書き込みにヘルパー関数を使用することがあります。これにより、データ構造がクリーンで保守しやすくなりますが、バッファの最後に複数のフィールドがある場合、うまくスケーリングできません。

代わりに次のようなことができれば、非常に役立ちます。

struct overlay {
    uint16_t field1;
    uint16_t field2;
    uint8_t  array1[ARY1_LEN];
    char     reserved[TOTAL_BUFFER_LENGTH -
                      offsetof(struct overlay, reserved) -
                      sizeof(uint32_t)];
    uint32_t crc;
};

残念ながら、offsetofは完全なオブジェクト型でしか機能しません。これは の定義の途中であるためstruct overlay、その型はまだ完全ではありません。

この種のことを行うための、よりクリーンで保守しやすい方法はありますか? 基本的に、最初と最後にフィールドがあり、残りのスペースが予約/未使用の固定長構造が必要です。

4

3 に答える 3

4

あなたの状況では、私はおそらくこのようにするだろうと思います:

typedef struct overlay_head
{
    uint16_t field1;
    uint16_t field2;
    uint8_t  array1[ARY1_LEN];
} overlay_head;

typedef struct overlay_tail
{
    uint32_t crc;
} overlay_tail;

enum { OVERLAY_RSVD = TOTAL_BUFFER_LENGTH - sizeof(overlay_head)
                                          - sizeof(overlay_tail) };

typedef struct overlay
{
    overlay_head h;
    uint8_t      reserved[OVERLAY_RSVD];
    overlay_tail t;
} overlay;

その後、ほとんど以前と同じように作業できますが、以前書いていた場所に を書き、以前書いていた場所に を書きp->field1 ます。p->h.field1p->crcp->t.crc

これは、頭と尾の両方が全体のサイズ内に収まる限り、任意の大きな尾構造を非常に効果的に処理することに注意してください。

于 2012-07-21T01:29:34.020 に答える
1

最後にCRCフィールドを持つバッファを持つ単純な構造を定義できます:

struct checked_buffer {
  char data[TOTAL_BUFFER_LENGTH - sizeof(uint32_t)];
  uint32_t crc;
};

data次に、そのフィールドに「オーバーレイ」を配置します。おそらく、生のバッファを に「変換」するポインタをすでにキャストchar*しているので、CRC フィールドにアクセスしたいときにからにoverlay*キャストするのは大したことではありません。overlay*checked_buffer*

しかし、一連の構造全体で一貫した位置にフィールドを配置したい場合は、各構造の先頭に配置する方が簡単です。そうすれば、奇妙なことをする必要なく、各構造体で直接宣言でき、それにアクセスするためのポインター キャストは必要ありません。

于 2012-07-21T00:26:15.537 に答える
0

どのようにそのことについて?

union a256
{
    struct
    {
        int field_a;
        int field_b;
        char name[16];
        // 
        int crcshadow;
    };

    struct
    {
        char buff[256-sizeof(int)];
        int crc;
    };
} ;

static_assert(offsetof(a256, crcshadow) < offsetof(a256, crc), "data too big");

最初の構造体にはデータが含まれ、2 番目の構造体はこの共用体の固定サイズを定義します。

于 2014-10-01T10:05:29.267 に答える