13

私は、ポータブル C89 でよく知られている「構造体ハック」のようなものを達成する方法を見つけたと信じています。これが本当に厳密に C89 に準拠しているかどうかに興味があります。

主なアイデアは次のとおりです。最初の構造体と配列の要素を保持するのに十分な大きさのメモリを割り当てます。正確なサイズは(K + N) * sizeof(array_base_type)で、は配列要素の数になるようにK選択されます。K * sizeof(array_base_type) >= sizeof(the_struct)N

最初に、malloc()store に返されたポインターを逆参照しthe_struct、次にポインター演算を使用して、構造体に続く配列の先頭へのポインターを取得します。

1 行のコードは 1000 語以上の価値があるため、最小限の実装を次に示します。

typedef struct Header {
    size_t length;
    /* other members follow */
} Header;

typedef struct Value {
    int type;
    union {
        int intval;
        double fltval;
    } v;
} Value;

/* round up to nearest multiple of sizeof(Value) so that a Header struct fits in */
size_t n_hdr = (sizeof(Header) + sizeof(Value) - 1) / sizeof(Value);

size_t n_arr = 42; /* arbitrary array size here */
void *frame = malloc((n_hdr + n_arr) * sizeof(Value));

if (!frame)
    return NULL;

Header *hdr = frame;
Value *stack_bottom = (Value *)frame + n_hdr;

私の主な懸念は、最後の 2 つの割り当て (frameヘッダーへのポインターと値へのポインターの両方として使用) が厳密なエイリアシング規則に違反する可能性があることです。ただし、hdrValue へのポインターとして逆参照はしません。frame値配列の最初の要素にアクセスするために実行されるのはポインター演算のみであるため、異なる型のポインターを使用して同じオブジェクトに効果的にアクセスすることはありません。

では、このアプローチは古典的な構造体ハック (公式には UB と見なされています) よりも優れているのでしょうか?それとも UB でしょうか?

4

1 に答える 1

5

「明白な」(まあ... まったく明白ではありませんが、とにかく私のHeader頭に浮かぶのは:-))これを壊す方法は、ベクトル化コンパイラーを使用して、たとえば 64をロードしても問題ないと判断することです42 から 64+ に切り上げられた領域からのベクトルhdrレジスタmalloc。ベクトル レジスタをメモリに戻すと、いずれかの が上書きされる可能性がありますValue

このベクトル化コンパイラーは、標準 (コンパイラーに指がある場合) を指し示し、準拠を主張できると思います。

ただし、実際には、このコードが機能することを期待しています。ベクトル化コンパイラーに遭遇した場合は、さらにスペースを追加して (最小値を挿入できるマシン依存のマクロで切り上げを行います)、充電してください。:-)

于 2013-08-19T15:21:55.327 に答える