Compilateur C, affirme - comment mettre en place?
J'aimerais mettre en œuvre un "faire valoir" qui empêche la compilation, plutôt que de ne pas au moment de l'exécution, dans le cas d'erreur.
J'ai actuellement défini comme ce qui fonctionne très bien, mais qui augmente la taille des fichiers binaires.
#define MY_COMPILER_ASSERT(EXPRESSION) switch (0) {case 0: case (EXPRESSION):;}
Exemple de code (qui ne peut pas compiler).
#define DEFINE_A 1
#define DEFINE_B 1
MY_COMPILER_ASSERT(DEFINE_A == DEFINE_B);
Comment puis-je mettre en œuvre cette opération afin qu'elle ne génère pas de code (dans le but de réduire la taille des fichiers binaires générés)?
- Je ne pense vraiment pas qu'il est possible de créer un statique affirmer dans la plaine, C, aimerais savoir si!
- Doublon avec plusieurs bonnes réponses: stackoverflow.com/questions/174356/...
- Depuis que cette question est relativement ancienne:
_Static_assert
et ses associés macrostatic_assert
sont standardisés de C11. C'est maintenant intégré à la langue. - Sûrement l'optimiseur peut jeter vide commutateurs.
Vous devez vous connecter pour publier un commentaire.
Au moment de la compilation affirmer dans le plus pur standard C est possible, et un peu de préprocesseur la ruse rend son utilisation un aspect tout aussi propre que le moteur d'exécution d'utilisation de
assert()
.La clé du problème est de trouver un concept qui peut être évaluée au moment de la compilation et peut causer une erreur pour certaines valeurs. Une seule réponse est la déclaration d'un tableau ne peut pas avoir une taille négative. À l'aide d'un typedef empêche la répartition de l'espace en cas de succès, et préserve de l'erreur en cas d'échec.
Le message d'erreur lui-même va sibylline de se référer à la déclaration d'une taille négative (GCC dit "la taille de la table foo est négatif"), si vous devez choisir un nom pour le type de tableau qui laisse deviner que cette erreur est vraiment une vérification d'assertion.
Un autre problème à gérer, c'est qu'il est seulement possible de
typedef
un type particulier de nom une fois dans toute unité de compilation. Ainsi, la macro doit arranger pour chaque utilisation pour obtenir un type unique nom à déclarer.Ma solution habituelle est d'exiger que la macro avoir deux paramètres. La première est la condition pour affirmer, c'est vrai, et le second est une partie du nom du type déclaré en coulisses. La réponse en plinthe des conseils à l'aide jeton de collage et de l'
__LINE__
macro prédéfinie pour former un nom unique, éventuellement, sans avoir besoin d'un argument supplémentaire.Malheureusement, si la vérification d'assertion est dans un fichier inclus, il peut encore entrer en collision avec un chèque dans le même numéro de ligne dans un deuxième fichier inclus, ou à ce numéro de la ligne dans le fichier source principal. Nous pourrions papier plus que par l'aide de la macro
__FILE__
, mais elle est définie à une constante de chaîne et il n'y a pas de préprocesseur astuce qui permet de transformer une chaîne de caractères constante de retour dans une partie d'un nom d'identificateur; pour ne pas mentionner que juridique des noms de fichier peut contenir des caractères qui ne sont pas des pièces d'un identificateur.Donc, je propose le fragment de code suivant:
Une utilisation typique pourrait être quelque chose comme:
Dans GCC, un échec d'assertion ressemblerait à:
Suivantes
COMPILER_VERIFY(exp)
macro fonctionne assez bien.Il fonctionne aussi bien le C et le C++ et peut être utilisé partout où un typedef serait autorisé. Si l'expression est vraie, il génère un typedef pour un tableau de 1 char (ce qui est sans danger). Si l'expression est fausse, il génère un typedef pour un tableau de -1 caractères, ce qui entraîne généralement un message d'erreur. L'expression donnée comme arugment peut être quelque chose qui donne une constante de compilation (donc les expressions impliquant sizeof() fonctionnent bien). Cela le rend beaucoup plus souple que
où vous êtes limité à des expressions qui peuvent être évalués par le préprocesseur.
Si votre compilateur définit une macro préprocesseur comme DEBUG ou NDEBUG vous pouvez faire quelque chose comme ça (sinon, vous pouvez configurer cela dans un Makefile):
Ensuite, votre compilateur affirme seulement pour les versions de débogage.
Le meilleur article que j'ai pu trouver sur la statique des assertions dans C est au pixelbeat. Notez que statique affirmations sont ajoutés pour C++ 0X, et peut le faire pour C1X, mais cela ne va pas être pour tout. Je ne sais pas si les macros dans le lien que j'ai donné à accroître la taille de vos fichiers binaires. Je soupçonne qu'ils ne seraient pas, au moins si vous compilez à un niveau raisonnable de l'optimisation, mais votre kilométrage peut varier.
Je sais que vous êtes intéressé à C, mais jetez un oeil à de boost C++ static_assert. (D'ailleurs, c'est probablement en train de devenir disponible en C++1x.)
Nous avons fait quelque chose de similaire, encore une fois, pour le C++:
Cela ne fonctionne qu'en C++, apparemment. Cet article décrit une manière de le modifier pour l'utiliser dans C.
Comme Leander dit, statique affirmations sont ajoutés à C++11, et maintenant ils ont.
static_assert(exp, message)
Par exemple
Voir le cppreference page sur elle.
_Static_assert
(voir stackoverflow.com/a/7287341/446106). En outre,assert.h
contient unstatic_assert
macro que des cartes à lui (en.cppreference.com/w/c/error/static_assert)Lors de la compilation de final binaires, définir MY_COMPILER_ASSERT d'être vide, de sorte que sa sortie n'est pas inclus dans le résultat. Seulement définir de la façon que vous avez pour le débogage.
Mais vraiment, vous n'allez pas être en mesure d'attraper chaque affirmation de cette façon. Certains n'ont pas de sens au moment de la compilation (comme l'affirmation qu'une valeur n'est pas nulle). Tout ce que vous pouvez faire est de vérifier les valeurs des autres #définit. Je ne suis pas vraiment sûr pourquoi vous voulez le faire.
En utilisant "#erreur " est valide définition de préprocesseur qui provoque la compilation de s'arrêter sur la plupart des compilateurs. Il vous suffit de faire comme ceci, par exemple, pour empêcher la compilation debug:
assert(sizeof(long) == sizeof(void *))
.J'ai trouvé ceci pour donner le moins déroutant message d'erreur de GCC. Tout le reste avait quelques suffixe négative de la taille ou de certains autres qui prête à confusion:
exemple d'utilisation:
Et le message d'erreur de gcc (BRAS/Compilateur C de GNU : 6.3.1):
Bien, vous pouvez utiliser le
statique affirme
dans la bibliothèque boost.Ce que je crois qu'ils y font, est de créer un tableau.
Si l'EXPRESSION est vraie, il définit
char x[1];
, qui est OK. Si la valeur est false, il définitchar x[0];
ce qui est illégal.#define MY_COMPILER_ASSERT(EXPRESSION) do {char x[(EXPRESSION)?1:-1];} while (0)
serait mieux: à l'intérieur d'accolades, de sorte que la déclaration est juridique et l'étendue des tailles 1 et -1 sont clairement valide/non valide sur tous les C versions, et vous oblige àMY_COMPILER_ASSERT(...);
avec un point-virgule de fin, pour garantir la cohérence visuelle avec toutes les autres fonction-comme les choses en C.