5

C 標準には次のように記載されています。

適切にキャストされた構造体オブジェクトへのポインターは、その最初のメンバー (または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。

問題の構造体の最初のメンバーが匿名の構造体/共用体である場合、C11でそのような「適切なキャスト」を実行する可能な(そして明確に定義された)方法はありますか? または、含まれている構造体が匿名の場合、「その逆」の後方キャストを実行するには?

匿名構造体と同じメンバーシーケンスを持つ非匿名構造体にキャストすると、互換性がないため、これが明確に定義されなくなり、同じメモリレイアウトを持つことが保証されないと思います。

ただし、C 標準には次のように記載されています。

さらに、別々の翻訳単位で宣言された 2 つの構造体、共用体、または列挙型は、それらのタグとメンバーが次の要件を満たしている場合に互換性があります。両方がそれぞれの翻訳単位内のどこかで完了している場合、次の追加要件が適用されます: メンバー間に 1 対 1 の通信が存在するものとします <...>

このルールを無名構造体に適用することはできますか? 次の設定があるとします。

header.h:

struct container {
    struct {
        int a;
        char b;
    };
};

void print(struct container *pcontainer);

9月c:

#include <stdio.h>
#include "header.h"

void print(struct container *pcontainer){
    printf("%d\n", ((struct { int a; char b; }*)pcontainer)->a);
}

main.c:

#include "header.h"

int main(void){
    struct container container, *pcontainer;

    pcontainer = &container;
    pcontainer->a = 1;

    print(pcontainer);

    return 0;
}

(これはgcc (GCC) 4.8.3 20140911でコンパイルされ、1 が出力されます)。

print関数内のキャストで使用される無名構造体と、 の最初のメンバーである無名構造体を考えてましょstruct container main.c。それらは「別々の翻訳単位で宣言された型」と見なすことができますか? また、他のすべての互換性要件を本当に満たしていますか、それとも何か誤解していますか?

4

1 に答える 1

2

翻訳単位とは:

5.1.1.1 プログラムの構造

  1. AC プログラムはすべて同時に翻訳する必要はありません。プログラムのテキストは、この国際規格ではソース ファイル (または前処理ファイル) と呼ばれる単位で保持されます。前処理ディレクティブ #include によって含まれるすべてのヘッダーとソース ファイルを含むソース ファイルは、前処理翻訳単位と呼ばれます。前処理後、前処理翻訳単位は翻訳単位と呼ばれます。

したがって、前処理後の c ファイルとヘッダーは、単一の翻訳単位を形成します。sep.cheader.hから作成される翻訳単位を見てみましょう。これには、 struct の 2 つの宣言が含まれています。1 つstruct { int a; char b; }は struct コンテナーにあり、もう 1 つは関数 print にあります。これらの構造体は、同じ翻訳単位で宣言されています。

6.2.7 互換型と複合型

  1. 型が同じ場合、2 つの型には互換性のある型があります。2 つの型に互換性があるかどうかを判断するための追加の規則は、型指定子については 6.7.2 で、型修飾子については 6.7.3 で、宣言子については 6.7.6 で説明されています。さらに、別々の翻訳で宣言された 2 つの構造体、共用体、または列挙型...

残りのテキストは、別の翻訳単位で宣言された型を参照しています。

構造体は個別の翻訳単位で宣言されていないため、6.2.7 規則には該当しません。

したがって、私の解釈では、構造体コンテナー内のものと print() 内のキャスト内のものは互換性がありません。

于 2015-01-13T16:46:38.717 に答える