web-dev-qa-db-fra.com

À quoi servent les structures et les unions anonymes dans C11?

C11 ajoute, entre autres, "Structures et unions anonymes".

J'ai fouillé, mais je n'ai pas pu trouver d'explication claire sur le moment où les structures et les unions anonymes seraient utiles. Je demande parce que je ne comprends pas complètement ce que c'est. Je comprends que ce sont des structures ou des unions sans nom par la suite, mais j'ai toujours (dû?) Traiter cela comme une erreur, donc je ne peux concevoir qu'une utilisation pour les structures nommées.

44
griotspeak

L'union anonyme à l'intérieur des structures est très utile dans la pratique. Considérez que vous voulez implémenter un type de somme discriminée (ou nion étiquetée ), un agrégat avec un booléen et soit un flottant soit un char* (c'est-à-dire une chaîne), selon le drapeau booléen. Avec C11, vous devriez pouvoir coder

typedef struct {
    bool is_float;
    union {
       float f;
       char* s;
    };
} mychoice_t;

double as_float(mychoice_t* ch) 
{ 
   if (ch->is_float) return ch->f;
   else return atof(ch->s);
}

Avec C99, vous devrez nommer l'union et coder ch->u.f et ch->u.s qui est moins lisible et plus verbeux.

50

Une utilisation typique et réelle des structures et des unions anonymes est de fournir une vue alternative aux données. Par exemple, lors de l'implémentation d'un type de point 3D:

typedef struct {
    union{
        struct{
            double x; 
            double y;
            double z;
        };
        double raw[3];
    };
}vec3d_t;

vec3d_t v;
v.x = 4.0;
v.raw[1] = 3.0; // Equivalent to v.y = 3.0
v.z = 2.0;

Ceci est utile si vous vous connectez au code qui attend un vecteur 3D comme pointeur vers trois doubles. Au lieu de faire f(&v.x) ce qui est moche, vous pouvez faire f(v.raw) ce qui rend votre intention claire.

40
Emily L.
struct bla {
    struct { int a; int b; };
    int c;
};

le type struct bla a un membre d'un type de structure anonyme C11.

struct { int a; int b; } n'a pas de balise et l'objet n'a pas de nom: c'est un type de structure anonyme.

Vous pouvez accéder aux membres de la structure anonyme de cette façon:

struct bla myobject;
myobject.a = 1;  // a is a member of the anonymous structure inside struct bla   
myobject.b = 2;  // same for b
myobject.c = 3;  // c is a member of the structure struct bla
7
ouah

Je ne sais pas pourquoi C11 autorise les structures anonymes à l'intérieur des structures. Mais Linux l'utilise avec ne certaine extension de langue :

/**
 * struct blk_mq_ctx - State for a software queue facing the submitting CPUs
 */
struct blk_mq_ctx {
    struct {
        spinlock_t      lock;
        struct list_head    rq_lists[HCTX_MAX_TYPES];
    } ____cacheline_aligned_in_smp;

    /* ... other fields without explicit alignment annotations ... */

} ____cacheline_aligned_in_smp;

Je ne sais pas si cet exemple est strictement nécessaire, sauf pour clarifier l'intention.

EDIT: J'ai trouvé un autre modèle similaire qui est plus clair. La fonction de structure anonyme est utilisée avec cet attribut:

#if defined(RANDSTRUCT_PLUGIN) && !defined(__CHECKER__)
#define __randomize_layout __attribute__((randomize_layout))
#define __no_randomize_layout __attribute__((no_randomize_layout))
/* This anon struct can add padding, so only enable it under randstruct. */
#define randomized_struct_fields_start  struct {
#define randomized_struct_fields_end    } __randomize_layout;
#endif

C'est à dire. un plugin d'extension de langage/compilateur pour randomiser l'ordre des champs (exploit de style ASLR "durcissement"):

struct kiocb {
    struct file     *ki_filp;

    /* The 'ki_filp' pointer is shared in a union for aio */
    randomized_struct_fields_start

    loff_t          ki_pos;
    void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
    void            *private;
    int         ki_flags;
    u16         ki_hint;
    u16         ki_ioprio; /* See linux/ioprio.h */
    unsigned int        ki_cookie; /* for ->iopoll */

    randomized_struct_fields_end
};
1
sourcejedi