私は、ポータブル 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
ヘッダーへのポインターと値へのポインターの両方として使用) が厳密なエイリアシング規則に違反する可能性があることです。ただし、hdr
Value へのポインターとして逆参照はしません。frame
値配列の最初の要素にアクセスするために実行されるのはポインター演算のみであるため、異なる型のポインターを使用して同じオブジェクトに効果的にアクセスすることはありません。
では、このアプローチは古典的な構造体ハック (公式には UB と見なされています) よりも優れているのでしょうか?それとも UB でしょうか?