web-dev-qa-db-ja.com

匿名の構造体/共用体を使用してCコードをコンパイルする方法は?

私はこれをC++/g ++で行うことができます:

struct vec3 { 
    union {
        struct {
            float x, y, z;
        }; 
        float xyz[3];
    }; 
};

その後、

vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);

働くでしょう。

Gccを使用してcでこれを行うにはどうすればよいですか?私が持っています

typedef struct {
    union {
        struct {
            float x, y, z;
        };
        float xyz[3];
    };
} Vector3;

しかし、特にエラーが発生します

line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
64
solinent

http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

-fms-extensionsは、あなた(そして私)が望む機能を有効にします。

51
user287561

(この回答はC11ではなくC99に適用されます)。

C99には匿名の構造体や共用体はありません。それらに名前を付ける必要があります:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

そして、それらにアクセスするときに名前を使用する必要があります。

assert(&v.data.xyz[0] == &v.data.individual.x);

この場合、最上位レベルの構造にはユニオン型の単一のアイテムがあるため、これを単純化できます。

typedef union {
    struct {
        float x, y, z;
    } individual;
    float xyz[3];
} Vector3;

データへのアクセスは次のようになります。

assert(&v.xyz[0] == &v.individual.x);
32

新しいC11規格は、匿名の構造と組合をサポートします。2011年4月のドラフトの序文パラグラフ6を参照してください。

http://en.wikipedia.org/wiki/C1X

奇妙な部分は、gccとclangの両方が、C89およびC99モードで匿名の構造とユニオンをサポートするようになったことです。私のマシンでは警告は表示されません。

25
hdante

また、いつでも次のことができます。

typedef struct
{
    float xyz[0];
    float x, y, z;
}Vec3;

長さゼロの配列はストレージを割り当てず、Cに「次に宣言されるものを指すように」だけを伝えます。次に、他の配列と同じようにアクセスできます。

int main(int argc, char** argv)
{
    Vec3 tVec;
    for(int i = 0; i < 3; ++i)
    {
        tVec.xyz[i] = (float)i;
    }

    printf("vec.x == %f\n", tVec.x);
    printf("vec.y == %f\n", tVec.y);
    printf("vec.z == %f\n", tVec.z);

    return 0;
}

結果:

vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000

過剰な妄想になりたい場合は、プラットフォームに合わせてデータパッキング戦略を手動で指定できます。

11

匿名結合はC++言語の機能です。 C言語には匿名の結合はありません。

匿名の構造体は、CにもC++にも存在しません。

質問で提示した宣言はGCC C++コンパイラでコンパイルできますが、コンパイラ固有の拡張であり、標準Cと標準C++のどちらとも関係ありません。

その上、どのように実装するかに関係なく、C言語もC++言語もアサーションが保持されることを保証しません。

8
AnT

警告なしでGCCでこれを行うことができます

typedef union {
    struct { // human-friendly access
        float x;
        float y;
        float z;
        float w;
    };
    float xyz[3];
    struct { // human-friendly access
        float r;
        float g;
        float b;
        float a;
    };
    float rgb[3];
} Vector4f;

int main()
{
    Vector4f position, normal, color;
    // human-friendly access
    position.x = 12.3f;
    position.y = 2.f;
    position.z = 3.f;
    position.w = 1.f;

    normal.x = .8f;
    normal.y = .9f;
    normal.z = .1f;
    normal.w = 1.f;

    color.r = 1.f;
    color.g = .233f;
    color.b = 2.11f;
    color.a = 1.1f;

    // computer friendly access
    //some_processor_specific_operation(position.vec,normal.vec);
    return 0;
}

C:\> gcc vec.c-壁

C:\> gcc --version gcc(GCC)4.4.0 Copyright(C)2009 Free Software Foundation、Inc.これはフリーソフトウェアです。コピー条件のソースを参照してください。保証はありません。市場性や特定の目的への適合性でさえも。

3
Afriza N. Arief

Cでは、匿名結合はサポートされていません。

また、次のように宣言する場合にも注意してください。

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

やること

Vector3 v;
v.data.xyz[0] = 5;

float foo = v.data.individual.x;

未定義の動作です。最後に割り当てられた組合員にのみアクセスできます。あなたの場合、標準で指定されていない多くのことに依存しているため、ユニオンの使用は間違っており、コーディング慣行が悪いです(パディング...)。

Cでは、次のようなものを好むでしょう。

typedef struct {
    float v[3];
} Vec3;

また、v [x]を使用したくない場合は、以下を検討できます。

#define X(V) ((V).v[0])

Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));
2
Nicolas Goy

ANSI/ISO C99標準ではない正体不明の構造体メンバーがこれを説明しますが、おもしろいことが起こることがわかります。GNU Cコンパイラ2.xxバージョンのポートでは、それらは、「xはunion\struct yのメンバーではありません、xとは何ですか?」などとは言いません。他の場合は、「xは未定義」、「xはstructのメンバーではありません」、これが原因で、「未知へのポインタ」を見たことがあると誓います。

したがって、私は専門的にこれについて全員と一緒に行き、struct\unionメンバーに識別子を与えるか、UNIONの場合は慎重にコードを再配置して、組合が特定された構造の特定されたメンバーと元の組合の未特定の構造に埋め込まれ、特定された構造のメンバーになり、特定された組合メンバーと慎重に使用されます。しかし、後者の方法が有効な代替手段ではない場合、これらのケースでは、私は単に厄介な構造に識別子を与えて先に進みます。

0
DLCJ

CのGNU方言は、匿名の構造体/共用体をサポートしますが、デフォルトでは、GCCは何らかの標準Cを使用してコンパイルします。GNU方言を使用するには、コマンドラインでstd = gnu99 ".

0
David Grayson