web-dev-qa-db-fra.com

Est-il possible d'écrire un _Static_assert dans GCC / GNU C qui vérifierait la disposition des champs de bits en mémoire au moment de la compilation?

Supposons que j'ai les définitions suivantes:

#include <stdbool.h>
#include <stdint.h>
#define ASSERT(cond) _Static_assert(cond, #cond)

typedef union {
    struct {
        bool bit0:1;
        bool bit1:1;
        bool bit2:1;
        bool bit3:1;
        bool bit4:1;
        bool bit5:1;
        bool bit6:1;
        bool bit7:1;
    };
    uint8_t bits;
} byte;

ASSERT(sizeof(byte) == sizeof(uint8_t));

Est-il possible d'écrire un code, tel que

#include <assert.h>
// ...
    assert(((byte) { .bit0 = 1 }).bits == 0b00000001);
    assert(((byte) { .bit1 = 1 }).bits == 0b00000010);
    assert(((byte) { .bit2 = 1 }).bits == 0b00000100);
    assert(((byte) { .bit3 = 1 }).bits == 0b00001000);
    assert(((byte) { .bit4 = 1 }).bits == 0b00010000);
    assert(((byte) { .bit5 = 1 }).bits == 0b00100000);
    assert(((byte) { .bit6 = 1 }).bits == 0b01000000);
    assert(((byte) { .bit7 = 1 }).bits == 0b10000000);
// ...

cela provoquerait un échec de compilation si les conditions ci-dessus n'étaient pas satisfaites?

(Lorsque j'essaye de placer les conditions dans la macro ASSERT, le compilateur se plaint que expression in static assertion is not constant, ce qui est bien sûr parfaitement logique)

La solution est autorisée à utiliser les extensions GNU du langage C.

8
Maciek Godek

Pas strictement dans les limites de la question, mais peut fournir une solution plus portable.

L'assertion statique a des limites aux expressions, et elle ne pourra PAS évaluer l'expression à partir d'une union.

Comme alternative, et en supposant que le code sera construit par un makefile (ou équivalent), envisagez d'ajouter une étape à la construction pour forcer la condition

static.verify: static_check.c
    cc -o static_check static_check.c
    ./static_check
    touch $@

    # Make the static.verify dependency for building objects/executable.
a.o: static.verify

Fondamentalement, il est nécessaire d'exécuter le petit programme 'static_check.c'. Le programme peut produire n'importe quel message d'erreur requis. Doit quitter avec un statut de retour différent de zéro pour indiquer une erreur.

0
dash-o