1

次のように指定された構造があります

  • メンバー 1、16 ビット
  • メンバー 2、32 ビット
  • メンバー 3、32 ビット

ファイルから読み取るものです。ファイルから構造体に直接読み込みたい。

問題は、次の構造体宣言のために ARM Cortex M3 で作業しているため、C コンパイラが変数 m1、m2、および m3 を 32 ビットのワード境界に揃えることです。

typedef struct
{
    uint16_t m1;
    uint32_t m2;
    uint32_t m3;
}something;

ファイルから直接読み取ると、m2 と m3 に間違った値が入力され、余分な 2 バイトも読み取られます。

私はハッキングして、現在問題なく動作する次のものを使用しています:

typedef struct
{
    uint16_t m1;
    struct
    {
        uint16_t lo;
        uint16_t hi;
    }m2;
    struct
    {
        uint16_t lo;
        uint16_t hi;
    }m3;
}something;

ただし、これは非常に汚いハックのように見えます。コンパイラに m2 と m3 の半分を別の単語に強制するよりクリーンな方法を望みますが、最適ではないかもしれません。

arm-none-eabi-gcc を使用しています。ビット パッキングについては知っていますが、この最適化を回避できません。

編集:ビットパッキングについて十分に知らなかったことがわかりました:D

4

4 に答える 4

1

このような構造体をファイルから直接読み取ることはできません。ミスアライメントは特定のアーキテクチャでトラップを引き起こす可能性があり、それを修正するためにプラグマに頼るべきではありません。

読み取りに使用しているのと同じアーキテクチャとアラインメント (少なくとも互換性がある) で構造体が記述されていることが確実でない限り、ファイル要素を構造体要素に読み取る場合のほぼ (*) 移植可能な方法。

だからあなたのユースケースのために、私はお勧めします:

fread(&something.m1, sizeof(something.m1), 1, fd);
fread(&something.m2, sizeof(something.m2), 1, fd);
fread(&something.m3, sizeof(something.m3), 1, fd);

(*) 必要に応じて正しいかどうかに関係なく、エンディアンの問題がないことを前提としているため、ほぼ移植可能です。1 つのマシンまたは 1 つのアーキテクチャを使用している場合は問題ありませんが、ビッグ エンディアンのマシンで struct を作成し、それをリトル エンディアンのマシンで読み取ると、問題が発生します...

于 2015-06-18T18:57:09.433 に答える
1

おそらく#pragma pack(2)。これにより、コンパイラは 2 バイト アラインメントを使用するようになります。

于 2015-06-18T18:43:14.213 に答える