要約すると、はい、C++ では違法ですが、C では有効です。後者には、違いを説明するこのメモが含まれています
変更: C++ では、戻り値またはパラメーターの型で型を定義できない場合があります。C では、これらの型定義が許可されています。
例:
void f( struct S { int a; } arg ) {} // valid C, invalid C++
enum E { A, B, C } f() {} // valid C, invalid C++
- 理論的根拠:異なるコンパイル単位で型を比較する場合、C が構造的な等価性に依存しているのに対し、C++ は名前の等価性に依存しています。パラメーターの型について: パラメーター リストで定義された型は関数のスコープ内にあるため、C++ での唯一の正当な呼び出しは関数自体からのものです。
- 元の機能への影響:意味的に明確に定義された機能の削除。
- 変換の難しさ:意味変換。型定義は、ファイル スコープまたはヘッダー ファイルに移動する必要があります。
- 広く使用されている方法:めったに使用されません。このスタイルの型定義は、不適切なコーディング スタイルと見なされます。
C における構造上の同等性は、「型の互換性」の概念によって行われます。これにより、C では多くの型を同一であるかのように扱うことができます。たとえそれらが理論的には異なっていても、2 つの異なる翻訳単位で宣言されているためです。C++ では、この概念は存在しません。型にはリンケージがあり、同じエンティティに一致するためです (つまり、メンバー関数が互いにリンクできるようにするため)。
上記の説明は、型の互換性を判断する際に構造体のタグ名を考慮しなかった C89 に基づいていることに注意してください。C89 ドラフトでは、関連するテキストは次のようになります。
さらに、別々の翻訳単位で宣言された 2 つの構造体、共用体、または列挙型は、同じ数のメンバー、同じメンバー名、および互換性のあるメンバー型を持っている場合、互換性があります。2 つの構造体の場合、メンバーは同じ順序でなければなりません。
C99 では、型チェックがより厳密になります。1 つの構造体にタグ名がある場合、もう 1 つの構造体宣言には同じタグ名が必要です。したがって、名前のない共用体型の場合、互換性のある型を持つ別の TU で関数を宣言するには、有効な C99 コード (未定義の動作なし) が必要な場合は、名前のない共用体が再び必要になります。「だます」ことはできません。ある TU で名前付き共用体を使用し、別の TU で無名共用体を使用します。ただし、この「トリック」はC89にも有効であるように見えます。C99 TC3 6.2.7/1
:
さらに、別々の翻訳単位で宣言された 2 つの構造体、共用体、または列挙型は、それらのタグとメンバーが次の要件を満たしている場合に互換性があります。両方とも完全な型である場合、次の追加要件が適用されます。対応するメンバーの各ペアが互換性のある型で宣言され、対応するペアの 1 つのメンバーが名前で宣言されている場合、他のメンバーは同じ名前で宣言されています。2 つの構造体の場合、対応するメンバーは同じ順序で宣言する必要があります。
あなたがやりたい方法はうまくいきません。関数を呼び出すと、通常の代入と同様に、引数がパラメーターの型に変換されます。
したがって、これが機能するには、パラメーターの型と互換性のある引数が必要です。同じ翻訳単位で宣言された 2 つの共用体の場合、これは、それらの型が等しくなければならないことを意味します。これが、同じ翻訳単位内で互換性のある型を見つける唯一の方法です。しかし、名前のない共用体の宣言は一意の新しい型を作成するため、これは機能しません。別の宣言を使用してそれを「参照」する方法はありません。
要約すると、共用体型に名前を付ける必要があります。必要な基本引数を渡すために別の変数を作成することを避けるために、関数の外で宣言し、渡す可能性のある共用体を返す関数を作成します。
union base_type {
uint16_t b16;
uint32_t b32;
uint64_t b64;
};
int pcg_new_state(pcg_state *s,int arch,void *mem,int sz,
union base_type base,int self_running);
union base_type base_b16(uint16_t t)
{ union base_type b; b.b16 = t; return b; }
union base_type base_b32(uint32_t t)
{ union base_type b; b.b32 = t; return b; }
union base_type base_b64(uint64_t t)
{ union base_type b; b.b64 = t; return b; }
今、それは次のようになります
pcg_new_state(...., base_b32(4211), ....);