4

ネストされた構造体内に柔軟な配列メンバーを持つことは有効な C コードですか? 以下のサンプル コードは、正常なコンパイラで期待どおりに動作することが保証されていますか?

#include <stdio.h>
#include <stdlib.h>

struct d {
    char c;
    int ns[];
};

struct c {
    struct d d;
};

struct b {
    struct c c;
};

struct a {
    int n;
    struct b b;
};

int main() {
    const int n = 10;
    struct a *pa = malloc(sizeof(*pa) + n * sizeof(pa->b.c.d.ns[0]));
    pa->n = n;
    pa->b.c.d.c = 1;
    for (int i = 0; i < n; ++i) {
        pa->b.c.d.ns[i] = i;
    }
    for (int i = 0; i < n; ++i) {
        printf("%d\n", pa->b.c.d.ns[i] + pa->b.c.d.c);
    }
    free(pa);
}
4

2 に答える 2

8

標準では無効です。実際にどれだけ信頼できるかはわかりません。

C11 (ISO/IEC 9899:2011)、§6.7.2.1.3 は次のように述べています (強調は私のものです):

構造体または共用体は、不完全型または関数型のメンバーを含んではなりません (したがって、構造体はそれ自体のインスタンスを含んではなりませんが、それ自体のインスタンスへのポインターを含むことができます) 。 1 つの名前付きメンバーの配列型が不完全な場合があります。そのような構造体 (およびそのような構造体であるメンバーをおそらく再帰的に含む共用体) は、構造体のメンバーまたは配列の要素であってはなりません。

後で、§6.7.2.1.18 は、上記がフレキシブル アレイ メンバー (FAM) を参照していることを明確にします。

特殊なケースとして、複数の名前付きメンバーを持つ構造体の最後の要素は、不完全な配列型を持つ場合があります。これはフレキシブル配列メンバーと呼ばれます。

いくつかの簡単な実験から、GCC と Clang は両方とも、FAM がネストされている場合でも FAM を適切に配置するために必要な末尾のパディングを追加し、FAMが渡されたstruct場合に他の構造体または配列のメンバーである構造体についてのみ警告するため、-Wpedanticあなたがそうするなら、それはおそらくうまくいくでしょう:)。ただし、少しハックな感じがします。

FAM を最後以外の場所に置くのはおそらく意味がないことに注意してください。もしあなたがそうするなら

struct e {
    struct d d;
    int n;
} e;

、その後e.d.ns[0]e.nメモリ内で重複する可能性があります。

于 2015-03-30T20:22:03.857 に答える