struct : déclarer des types et des variables en C

On utilise quasi-systématiquement des structures dans un programme en C. Cet article montre un maximum d’utilisations du mot-clé struct, en aide-mémoire pour moi-même et pour tous ceux qui en auront l’utilité 😉

La définition d’un nouveau type de structure est simple en C, avec le mot-clé struct :

struct [nom du type structuré]
{
   type nom_champ;
   type nom_champ;
   ...
   type nom_champ;
} [un ou plusieurs noms de variables];

Le mot-clé struct permet de définir un nouveau type, on peut ajouter un nom optionnel pour ce type, on liste les champs avec un nom et un type (comme une déclaration de variable) en les séparant par des points-virgules, et enfin on donne un ou plusieurs noms de variables (c’est aussi une option) qui seront de ce nouveau type structuré. Un code pour illustrer cela :

#include <stdio.h>

// Creation d'un type nommé de structure
struct premier_type
{
    int champ;
};

// Création d'un type anonyme sans déclarer de variable
// C'est sans effet et le compilateur le dit
struct
{
	int champ;
};

int main()
{
	// Déclaration d'une variable de type "struct premier_type"
	struct premier_type a;

	// Accès au champ de la structure avec l'opérateur .
	a.champ = 42;

    // Creation d'une structure mais dont le type est anonyme et donc non réutilisable
    struct
	{
        int champ;
    } b;
    b.champ = a.champ + 1;

    // Creation d'un type reutilisable localement
    // (sa portée est limitée à la fonction courante) et de variables
    // Comme toute déclaration de variable, on peut ajouter une initialisation
    struct troisieme_type
	{
        int un;
        int deux;
        int trois;
    } c = {20, 18, 6}, d;

    d.un = a.champ;
    d.deux = b.champ;
    d.trois = c.un + c.deux + c.trois;

    printf("d: %d %d %d", d.un, d.deux, d.trois);
}

Le compilateur émet un warning :

../src/structures.c:11:1: warning: declaration does not declare anything
 [-Wmissing-declarations]

En effet, le nom du type et la déclaration de variables sont tous les deux optionnels, mais si on n’utilise ni l’un ni l’autre, cela ne sert à rien. Il faut au moins mettre au moins l’un des deux, vous vous en étiez douté.

La sortie console est comme attendue :

d: 42 43 44

Quand on utilise des structures, le mot-clé typedef n’est généralement pas très loin. En effet, il permet de donner un nom plus simple à un type existant. Il permet par exemple de remplacer struct nom_type par alias_type et donc d’alléger le code. typedef s’utilise ainsi :

typedef nom_type_existant alias_type

Le nom originel et l’alias sont du même type réel, on peut donc mixer des variables des deux « types ». Pour les structures, on aura du code comme ceci :

#include <stdio.h>

// Creation d'un type de structure puis creation d'un alias
struct premier_type
{
    int champ;
};

typedef struct premier_type alias_premier_type;

// Creation d'un type et de l'alias en meme temps
// L'alias peut être identique au nom du type
typedef struct second_type
{
    int champ;
} second_type;

// Creation d'un type anonyme et d'un alias
typedef struct
{
	int champ;
} troisieme_type;

int main()
{
    // On peut utiliser conjointement le type ou son alias
    struct premier_type a = {1};
    alias_premier_type b = a;

    struct second_type c = {2};
    second_type d = c;

    // Ici, on ne peut utiliser que l'alias car lui seul est connu
    troisieme_type e = {3};

    // Un type peut avoir plusieurs alias ; on peut créer un alias localement
    typedef struct second_type autre_alias;
    autre_alias f = d;

    printf("b --> %d\n", b.champ);
    printf("d --> %d\n", d.champ);
    printf("e --> %d\n", e.champ);
    printf("f --> %d\n", f.champ);
}

Encore une fois, pas de surprise quant à la sortie console :

b --> 1
d --> 2
e --> 3
f --> 2

J’ai écrit quelques autres articles sur les structures en C, qui pourront aussi vous intéresser 😉

Publicités

Une Réponse

  1. Salut!
    Tu as encore au moins un ou deux articles à écrire avant d’avoir fait le tour de la question 🙂

    D’abord sur l’alignement en mémoire des membres d’une structure et la façon de gagner de la RAM en mettant les champs dans le bon ordre. Par exemple:

    struct foo {
    char a;
    int b;
    };

    Comme l’entier b est aligné sur 32 bits, il y aura 3 octets « vides » dans cette struct. Par contre:

    struct bar {
    int b;
    char a;
    };

    ne pose pas ce problème. Alors ça ne change pas grand chose quand il n’y a que 2 champs, mais sur une grosse struct ou on alterne et mélange des booléens, des char et des int, on a vite fait de perdre quelques dizaines d’octets par instance. Donc, une optimisation facile à faire et avec peu d’incidence sur la lisibilité du code.

    Ensuite, sur les bitfields:

    struct foo {
    char a :4;
    char b :4;
    };

    Ici une structure avec deux fields de 4 bits chacun. Elle tient donc sur un octet. Là aussi, c’est un gain de mémoire possible quand on ne stocke que des petites valeurs (ou des flags). Par contre il y a un coût en temps d’exécution (puisqu’il faut traiter les accès à ces structs de façon particulière, en masquant les bits appropriés.

    Sur les unions et la possibilité de les utliser avec des struc anonymes:

    struct foo {
    union {
    struct {
    uint16_t low;
    uint16_t high;
    },
    uint32_t full
    }
    };

    on peut accéder à foo.low, foo.high, ou foo.full. Pratique dans certains cas pour éviter des conversions à coup de cast de pointeurs (mais attention à l’endianness). On peut également utiliser ce genre de choses pour faire une structure « à type variable », qui contient un ensemble de fields, ou un autre. Grace aux unions et aux structs anonymes c’est possible de façon claire et lisible. Contrairement à l’aPI sockets BSD et ses sockaddr_storage et autres joyeusetés (mais tout ceci n’existait pas en C89 et encore moins en C K&R).

    J'aime

    2 février 2015 à 8:33

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s