pour - programme langage c




Qu'est-ce que ":-!!" en code C? (4)

C'est, en effet, un moyen de vérifier si l'expression e peut être évaluée à 0, et sinon, d'échouer à la construction .

La macro est un peu mal nommée; il devrait être quelque chose de plus comme BUILD_BUG_OR_ZERO , plutôt que ...ON_ZERO . (Il y a eu des discussions occasionnelles sur la question de savoir si c'est un nom déroutant .)

Vous devriez lire l'expression comme ceci:

sizeof(struct { int: -!!(e); }))
  1. (e) : Expression de calcul e .

  2. !!(e) : Annule deux fois logiquement: 0 si e == 0 ; sinon 1 .

  3. -!!(e) : Annule numériquement l'expression de l'étape 2: 0 si elle était 0 ; sinon -1 .

  4. struct{int: -!!(0);} --> struct{int: 0;} : Si elle était nulle, alors nous déclarons une structure avec un bitfield entier anonyme de largeur zéro. Tout va bien et nous procédons comme d'habitude.

  5. struct{int: -!!(1);} --> struct{int: -1;} : D'un autre côté, si ce n'est pas zéro, alors ce sera un nombre négatif. Déclarer un champ de bit avec une largeur négative est une erreur de compilation.

Donc nous finirons soit avec un bitfield de largeur 0 dans un struct, ce qui est bien, soit un bitfield avec une largeur négative, ce qui est une erreur de compilation. Ensuite, nous prenons sizeof ce champ, donc nous obtenons un size_t avec la largeur appropriée (qui sera nulle dans le cas où e est zéro).

Certaines personnes ont demandé: Pourquoi ne pas simplement utiliser une assert ?

La réponse de Keithmo ici a une bonne réponse:

Ces macros implémentent un test de compilation, tandis que assert () est un test d'exécution.

Exactement juste. Vous ne voulez pas détecter des problèmes dans votre noyau au moment de l'exécution qui auraient pu être détectés plus tôt! C'est un élément essentiel du système d'exploitation. Dans quelle mesure les problèmes peuvent être détectés au moment de la compilation, tant mieux.

Je suis tombé sur ce code de macro étrange dans /usr/include/linux/kernel.h :

/* Force a compilation error if condition is true, but also produce a
   result (of value 0 and type size_t), so the expression can be used
   e.g. in a structure initializer (or where-ever else comma expressions
   aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

Qu'est-ce que :-!! faire?


Certaines personnes semblent confondre ces macros avec assert() .

Ces macros implémentent un test de compilation, tandis que assert() est un test d'exécution.


Il crée un bitfield de taille 0 si la condition est fausse, mais un -1 taille -1 ( -!!1 ) si la condition est vraie / non nulle. Dans le premier cas, il n'y a pas d'erreur et la structure est initialisée avec un membre int. Dans le dernier cas, il y a une erreur de compilation (et rien de tel qu'un champ de taille -1 n'est créé, bien sûr).


Le : est un bitfield. Quant à !! , c'est la double négation logique et donc retourne 0 pour faux ou 1 pour vrai. Et le - est un signe moins, c'est-à-dire la négation arithmétique.

Tout est juste une astuce pour obtenir le compilateur à barf sur les entrées invalides.

Envisager BUILD_BUG_ON_ZERO . Quand -!!(e) évalue à une valeur négative, cela produit une erreur de compilation. Sinon -!!(e) évalue à 0, et un champ de largeur 0 a une taille de 0. Et donc la macro évalue à size_t avec la valeur 0.

Le nom est faible à mon avis parce que la construction échoue quand l'entrée n'est pas nulle.

BUILD_BUG_ON_NULL est très similaire, mais donne un pointeur plutôt qu'un int .





linux-kernel