1

構造体のメンバーは、宣言に出現する順序で構造体内に割り当てられ、昇順のアドレスを持ちます。

私は次のジレンマに直面しています: 構造体を宣言する必要があるとき、私は

(1) フィールドを論理的にグループ化する、または

(2) サイズが小さい順に、RAM と ROM のサイズを節約するには?

以下は、最大のデータ メンバーを一番上に配置する必要がある例ですが、論理的に接続された とグループ化する必要もありますcolour

struct pixel{
    int posX;
    int posY;

    tLargeType ColourSpaceSecretFormula;
    char colourRGB[3];
}

構造体のパディングは非決定論的 (つまり、実装依存) であるため、構造体要素に対してポインター演算を確実に実行することはできません (また、そうすべきではありません: 誰かが自分の好みに合わせてフィールドを並べ替えると想像してみてください: BOOM、コード全体動作を停止します)。

-fpack-structsは gcc でこれを解決しますが、他の制限があるため、コンパイラ オプションは問題外にします。

一方、コードは何よりも読みやすくなければなりません。マイクロ最適化は絶対に避けるべきです。

では、構造体のメンバーが標準によって順序付けられているのはなぜでしょうか。特定の方法で構造体メンバーを順序付けするマイクロ最適化について心配していますか?

4

3 に答える 3

3

コンパイラは、いくつかの伝統的および実際的な制限によって制限されています。

キャスト後の構造体へのポインター (標準では「適切に変換された」と呼ばれます) は、構造体の最初の要素へのポインターと等しくなります。これは、メッセージ パッシングでメッセージのオーバーロードを実装するためによく使用されます。その場合、構造体には、残りの構造体の型とサイズを記述する最初の要素があります。

最後の要素は、動的にサイズ変更された配列にすることができます。公式言語がサポートされる前から、これは実際によく使用されていました。sizeof(struct) + length of extra data割り当てた要素と同じ数の要素を持つ通常の配列として、最後の要素を割り当ててアクセスできます。

これら 2 つのことにより、コンパイラは構造体の最初と最後の要素を、宣言されているのと同じ順序で持つように強制されます。

もう 1 つの実際的な要件は、すべてのコンパイルで構造体メンバーを同じ方法で順序付けする必要があることです。スマート コンパイラは、一部の構造体メンバーが常に互いに近くでアクセスされることがわかっているため、最終的にキャッシュ ラインになるように並べ替えることができるという決定を下すことができます。構造体はしばしば異なるコンパイル単位間で API を定義するため、この最適化はもちろん C では不可能であり、異なるコンパイルで異なる順序で並べ替えることができないためです。

制限を考慮してできる最善の方法は、ABI である種のパッキング順序を定義して、構造体の最初または最後の要素に触れない配置の無駄を最小限に抑えることですが、それは複雑でエラーが発生しやすく、おそらくそうではないでしょう。たくさん買う。

于 2013-04-25T12:55:56.107 に答える
2

順序付けに頼ることができなければ、ハードウェア レジスタ、ネットワーク パケット、外部ファイル形式、ピクセル バッファなどに構造をマッピングする低レベル コードを記述するのは非常に難しくなります。

また、一部のコードでは、構造体の最後のメンバーがメモリ内で最もアドレス指定されていると想定して、はるかに大きなデータ ブロック (コンパイル時のサイズが不明) の開始を示すトリックを使用します。

于 2013-04-25T12:13:01.673 に答える
1

構造体のフィールドを並べ替えると、特に 64 ビット メモリ モデルでは、データ サイズが大きくなり、多くの場合コード サイズも大きくなります。以下に説明する例を示します (一般的なアライメント規則を想定):

struct list {
   int  len;
   char *string;
   bool isUtf;
};

32ビットモードでは12バイト、64ビットモードでは24バイトかかります。

struct list {
   char *string;
   int  len;
   bool isUtf;
};

32 ビットでは 12 バイトを使用しますが、64 ビット モードでは 16 バイトしか使用しません。

これらの構造体の配列がある場合、データだけでなくコード サイズも 50% 増加します。これは、2 の累乗でのインデックス付けが他のサイズよりも単純であるためです。構造がシングルトンであるか、頻繁ではない場合、フィールドを並べ替えてもあまり意味がありません。使用頻度が高い場合は要チェックポイントです。

あなたの質問の他の点について。コンパイラがこのフィールドの並べ替えを行わないのはなぜですか。その場合、共通のパターンを使用する構造体の共用体を実装するのが難しいからです。たとえばのように。

struct header {
    enum type;
    int  len;
};

struct a {
    enum type;
    int  len;
    bool whatever1;
};

struct b {
    enum type;
    int  len;
    long whatever2;
    long whatever4;
};

struct c {
    enum type;
    int  len;
    float fl;
};


 union u {
    struct h header;
    struct a a;
    struct b b;
    struct c c;
 };

コンパイラがフィールドを再配置した場合、に含まれる異なる構造体を介して および フィールドにアクセスするときにtypeおよびフィールドが同一であるという保証がないため、この構造はさらに不便になります。私の記憶が正しければ、標準でもこの動作が義務付けられています。lenunion

于 2013-04-25T12:56:38.037 に答える