次のような構成の使用を推測することはできません
struct
{
uint64_t offsets[0];
} table;
これに関するヒントを教えてください。
投稿したコードは正式に無効です。正式には、C言語はサイズの配列をサポートしていません0
。
一部のコンパイラ(ルーズ/レガシーエラーチェック付き)では、構造体の最後にサイズ0の配列を許可します。これは、いわゆる「構造体ハック」を実装するために使用されることがありました。(より良いアプローチは、サイズ1の末尾の配列を使用することです。)ただし、宣言ではその使用は規定されていません。「構造体ハック」には名前付きの構造体タイプが必要であり、実際のオブジェクトは動的に割り当てられる必要があります。あなたの場合、構造体タイプは名前なしのままであり、変数table
は非動的に定義されています。したがって、コードを正しく再現したと仮定すると、「structhack」はここでは問題外です。
table
したがって、コンパイルしても、使用可能なデータを含まない変数になってしまいます。この変数の唯一の使用法(静的ストレージ期間で宣言されている場合)は、&table
式(「匿名構造体へのポインター」タイプのポインター)を介して一意のアドレス定数を生成することです。
宣言を「構造体ハック」に近いものに変える1つの方法は、そのtypedef
前にを追加することです。
typedef struct
{
uint64_t offsets[0];
} table;
ただし、「構造体ハック」の「人間が生成した」構造体宣言には、通常、柔軟な配列宣言の前に他のデータフィールドが含まれます(これらがないと、通常の配列よりも「構造体ハック」を選択しても意味がありません)。
これは、任意のサイズのメモリブロックをポインタ型にキャストし、最後の配列メンバーを可変長配列にするためのトリックです。おそらく標準ではありませんが、C配列は境界チェックされていないため、これは機能します。
これを示す非常に簡単な例を次に示します。
typedef struct Foo
{
int count;
int array[0];
} Foo;
Foo* foo = (Foo*)malloc(sizeof(Foo) + 5 * sizeof(int));
foo->count = 5;
次に、このフィールドを使用して、count
内の有効な要素の数を知ることができFoo*
ます。前述のように、C配列は境界チェックされていないため、コンパイラーもランタイムも、foo->array
読み取りまたは書き込みを試みたときにサイズが0の配列をキャッチしません。
名前なしを定義したのは、struct
実際には名前table
ではなくオブジェクトstruct
です。
だから、あなたがこの宣言を持っているなら
typedef struct
{
uint64_t offsets[0];
} table;
または、
struct table
{
uint64_t offsets[0];
} table;
次に、これは可変長配列と呼ばれます(struct hackと呼ばれます)。
構造体の最後のメンバーである必要があるという制限があります。