web-dev-qa-db-fra.com

Comment compiler du code C avec des structures / unions anonymes?

Je peux le faire en c ++/g ++:

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

Ensuite,

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

marchera.

Comment fait-on cela en c avec gcc? j'ai

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

Mais je reçois des erreurs tout autour, en particulier

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

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

-fms-extensions activera la fonctionnalité que vous (et moi) voulons.

51
user287561

(Cette réponse s'applique à C99, pas à C11).

C99 n'a pas de structures ou de syndicats anonymes. Vous devez les nommer:

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

Et puis vous devez utiliser le nom lorsque vous y accédez:

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

Dans ce cas, parce que votre structure de niveau supérieur a un seul élément de type union, vous pouvez simplifier ceci:

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

et accéder aux données devient maintenant:

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

La nouvelle norme C11 soutiendra les structures anonymes et les syndicats, voir le paragraphe 6 de l'avant-projet du projet d'avril 2011.

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

La partie étrange est que gcc et clang prennent désormais en charge les structures anonymes et les unions en mode C89 et C99. Dans ma machine, aucun avertissement n'apparaît.

25
hdante

On peut également toujours faire ce qui suit:

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

Le tableau de longueur nulle n'alloue aucun stockage et indique simplement à C de "pointer vers la prochaine chose déclarée". Ensuite, vous pouvez y accéder comme n'importe quel autre tableau:

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;
}

Résultat:

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

Si vous voulez être paranoïaque supplémentaire, vous pouvez spécifier manuellement la stratégie de compression des données en fonction de votre plate-forme.

11
Ionoclast Brigham

Les unions anonymes sont une fonctionnalité du langage C++. Le langage C n'a pas d'unions anonymes.

Les structures anonymes n'existent ni en C ni en C++.

La déclaration que vous avez présentée dans votre question peut être compilée avec GCC C++ complier, mais ce ne serait qu'une extension spécifique au compilateur, qui n'a rien à voir avec ni le C standard ni le C++ standard.

De plus, quelle que soit la façon dont vous l'implémentez, ni le langage C ni le langage C++ ne garantissent que vos assertions tiendront.

8
AnT

Je peux le faire dans GCC sans avertissement

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 -Wall

C: \> gcc --version gcc (GCC) 4.4.0 Copyright (C) 2009 Free Software Foundation, Inc. Il s'agit d'un logiciel libre; voir la source pour les conditions de copie. Il n'y a AUCUNE garantie; pas même pour la QUALITÉ MARCHANDE ou l'aptitude à un usage particulier.

3
Afriza N. Arief

Les syndicats Anonymouse ne sont pas soutenus en C.

Notez également que si vous le déclarez de cette façon:

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

Faire

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

float foo = v.data.individual.x;

Est un comportement indéfini. Vous ne pouvez accéder qu'au dernier membre du syndicat affecté. Dans votre cas, l'utilisation d'une union est une mauvaise et mauvaise pratique de codage car elle dépend de beaucoup de choses qui ne sont pas spécifiées dans la norme (padding ...).

En C, vous préférerez quelque chose comme ceci:

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

Et si vous ne voulez pas utiliser v [x], vous pourriez envisager:

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

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

Les membres de structure non identifiés qui ne sont pas la norme ANSI/ISO C99 l'expliquent, mais je trouve une drôle de chose qui se produit, sur certains ports des versions GNU C Compiler 2.xx, en utilisant des membres de structure non identifiés, cela trouve eux, ne dit pas des trucs comme "x n'est pas membre de l'union\struct y, qu'est-ce que x?", d'autres fois, c'est l'ol '"x n'est pas défini", "x n'est pas membre de struct", enfer Je jure avoir vu un "pointeur vers l'inconnu" de temps en temps, à cause de cela.

Donc, professionnellement, j'irais avec tout le monde à ce sujet et je donnerais simplement un identifiant au membre struct\union, ou dans le cas des UNIONS, réorganiser soigneusement le code afin que le syndicat devienne un membre identifié d'une structure identifiée et les membres qui ont été intégrés dans la structure non identifiée du syndicat d'origine, sont devenus membres de la structure identifiée et sont soigneusement utilisés avec le membre du syndicat identifié. Mais dans ces cas, si cette dernière méthode ne serait pas un substitut réalisable, je donnerais simplement un identifiant à la structure ennuyeuse et passer à autre chose.

0
DLCJ

Le dialecte GNU de C prend en charge les structures/unions anonymes, mais par défaut GCC compile en utilisant une sorte de C. standard. Pour utiliser le dialecte GNU, mettez "- std = gnu99 "sur la ligne de commande.

0
David Grayson