1

次の例を検討してください。

typedef struct test_flex_arr{
    size_t sz;
    struct {
        int i;
        const char *path;
    } info[];
} tfa;

int main(void){
    size_t sz = 100;
    tfa *ptr = malloc(sizeof *ptr + sizeof (*((tfa*) NULL)).info[sz]);
    ptr->info[99].i = 10;
    printf("%d\n", ptr->info[99].i); //prints 10
}

デモ

このプログラムはクラッシュするだろうと思っていましたが、問題なく動作します。指定された6.5.3.4(p2)とおり:

このsizeof演算子は、そのオペランドのサイズ (バイト単位) を返します。これは、式または括弧で囲まれた型の名前の場合があります。サイズは、オペランドの型から決定されます。結果は整数です。オペランドの型が可変長配列型の場合、オペランドは評価されます。それ以外の場合、オペランドは評価されず、結果は整数定数になります

のオペランドの型sizeof ((*((tfa*) NULL)).info)[sz]は可変長配列であるため、オペランドを評価する必要があります。しかし、オペランドの評価は、NULLクラッシュにつながると予想していた逆参照を意味します。

コードの動作は明確に定義されていますか?

4

1 に答える 1

8

(*((tfa*) NULL)).info[sz]は型ではないため、可変長配列型で(*((tfa*) NULL)).infoはありません。

szつまり、配列の要素を参照して、それを通常の式として扱ってい(*((tfa*) NULL)).infoます。引用された仕様によると、これは評価されないため、逆参照NULLしても未定義の動作は発生しません。配列要素のサイズを返すだけで、配列の場所やインデックスに依存しません。そのため、警告なしでコンパイルされ、クラッシュしません。

しかし、これでは望ましい結果が得られません。sz実際にスペースを割り当てる必要がある要素ではなく、配列の 1 つの要素のサイズのみを取得しています。要素のサイズに要素の数を掛ける必要があります。だから使う

tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);
于 2019-05-13T21:09:34.917 に答える