Existe-t-il un moyen d'utiliser une sizeof
macro dans une macro de préprocesseur?
Par exemple, il y a eu une tonne de situations au fil des ans dans lesquelles je voulais faire quelque chose comme:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
La chose exacte que je vérifie ici est complètement inventée - le fait est que j'aime souvent mettre ces types de vérifications au moment de la compilation (taille ou alignement) pour me prémunir contre quelqu'un qui modifie une structure de données qui pourrait désaligner ou ré-aligner dimensionner les choses qui les briseraient.
Inutile de dire que je ne semble pas être en mesure d'utiliser un sizeof
de la manière décrite ci-dessus.
Réponses:
Il existe plusieurs façons de procéder. Les extraits de code suivants ne produiront aucun code s'ils sont
sizeof(someThing)
égauxPAGE_SIZE
; sinon, ils produiront une erreur de compilation.1. Voie C11
À partir de C11, vous pouvez utiliser
static_assert
(nécessite#include <assert.h>
).Usage:
2. Macro personnalisée
Si vous souhaitez simplement obtenir une erreur de compilation alors que ce
sizeof(something)
n'est pas ce à quoi vous vous attendez, vous pouvez utiliser la macro suivante:Usage:
Cet article explique en détail pourquoi cela fonctionne.
3. Spécifique à MS
Sur le compilateur Microsoft C ++, vous pouvez utiliser la macro C_ASSERT (requiert
#include <windows.h>
), qui utilise une astuce similaire à celle décrite dans la section 2.Usage:
la source
gcc
(testé à la version 4.8.4) (Linux). Au niveau des((void)sizeof(...
erreurs avecexpected identifier or '(' before 'void'
etexpected ')' before 'sizeof'
. Mais en principe, fonctionnesize_t x = (sizeof(...
plutôt comme prévu. Vous devez "utiliser" le résultat, d'une manière ou d'une autre. Pour permettre à cela d'être appelé plusieurs fois à l'intérieur d'une fonction ou à une portée globale, quelque chose commeextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
peut être utilisé à plusieurs reprises (pas d'effets secondaires, ne référencez à_BUILD_BUG_ON_
aucun endroit).Non. Les directives conditionnelles acceptent un ensemble restreint d'expressions conditionnelles;
sizeof
est l'une des choses interdites.Les directives de prétraitement sont évaluées avant que la source ne soit analysée (du moins sur le plan conceptuel), il n'y a donc pas encore de types ou de variables pour obtenir leur taille.
Cependant, il existe des techniques pour obtenir des assertions au moment de la compilation en C (par exemple, voir cette page ).
la source
Je sais que c'est une réponse tardive, mais pour ajouter à la version de Mike, voici une version que nous utilisons qui n'alloue aucune mémoire. Je n'ai pas trouvé le contrôle de taille d'origine, je l'ai trouvé sur Internet il y a des années et je ne peux malheureusement pas faire référence à l'auteur. Les deux autres ne sont que des extensions de la même idée.
Parce qu'ils sont typedef, rien n'est alloué. Avec le __LINE__ dans le nom, c'est toujours un nom différent afin qu'il puisse être copié et collé si nécessaire. Cela fonctionne dans les compilateurs MS Visual Studio C et les compilateurs GCC Arm. Cela ne fonctionne pas dans CodeWarrior, CW se plaint de la redéfinition, n'utilisant pas la construction de préprocesseur __LINE__.
la source
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Je sais que ce fil est vraiment vieux mais ...
Ma solution:
Tant que cette expression équivaut à zéro, elle se compile correctement. Tout le reste et ça explose juste là. Parce que la variable est externe, elle ne prendra pas d'espace, et tant que personne ne la référence (ce qui n'est pas le cas), cela ne provoquera pas d'erreur de lien.
Pas aussi flexible que la macro assert, mais je ne pouvais pas faire compiler cela dans ma version de GCC et cela le sera ... et je pense qu'il se compilera à peu près n'importe où.
la source
Les réponses existantes montrent simplement comment obtenir l'effet des «assertions à la compilation» en fonction de la taille d'un type. Cela peut répondre aux besoins de l'OP dans ce cas particulier, mais il existe d'autres cas où vous avez vraiment besoin d'un préprocesseur conditionnel basé sur la taille d'un type. Voici comment procéder:
Écrivez-vous un petit programme C comme:
Compilez ça. Écrivez un script dans votre langage de script préféré, qui exécute le programme C ci-dessus et capture sa sortie. Utilisez cette sortie pour générer un fichier d'en-tête C. Par exemple, si vous utilisiez Ruby, cela pourrait ressembler à:
Ensuite, ajoutez une règle à votre Makefile ou à un autre script de construction, ce qui le fera exécuter le script ci-dessus pour construire
sizes.h
.Incluez
sizes.h
là où vous avez besoin d'utiliser des conditions de préprocesseur basées sur des tailles.Terminé!
(Avez-vous déjà tapé
./configure && make
pour créer un programme? Ce queconfigure
font les scripts est essentiellement comme ci-dessus ...)la source
Qu'en est-il de la prochaine macro:
Par exemple, dans le commentaire, MSVC dit quelque chose comme:
la source
#if
directive de préprocesseur.Juste à titre de référence pour cette discussion, je signale que certains compilateurs obtiennent sizeof () ar du temps pré-processeur.
La réponse de JamesMcNellis est correcte, mais certains compilateurs passent par cette limitation (cela viole probablement le strict ansi c).
Dans ce cas, je me réfère au compilateur IAR C (probablement le principal pour le microcontrôleur professionnel / la programmation embarquée).
la source
sizeof
au moment du prétraitement.sizeof
doit être traité comme un simple identifiant.#if (sizeof(int) == 8)
fonctionnaient réellement (sur certains compilateurs)." La réponse: "Ça devait être avant mon temps.", Était de Dennis Ritchie.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
pourrait fonctionnerla source
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
condition. Cela ne donne aucun avantagesizeof(x)
.En C11, le
_Static_assert
mot clé est ajouté. Il peut être utilisé comme:la source
Dans mon code c ++ portable ( http://www.starmessagesoftware.com/cpcclibrary/ ) je voulais mettre une garde sur la taille de certaines de mes structures ou classes.
Au lieu de trouver un moyen pour le préprocesseur de lancer une erreur (qui ne peut pas fonctionner avec sizeof () comme indiqué ici), j'ai trouvé ici une solution qui fait que le compilateur génère une erreur. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
J'ai dû adapter ce code pour qu'il génère une erreur dans mon compilateur (xcode):
la source
Après avoir essayé les macros mentionnées, ce fragment semble produire le résultat souhaité (
t.h
):Courir
cc -E t.h
:Courir
cc -o t.o t.h
:42 n'est pas la réponse à tout après tout ...
la source
Pour vérifier au moment de la compilation la taille des structures de données par rapport à leurs contraintes, j'ai utilisé cette astuce.
Si la taille de x est supérieure ou égale à sa limite MAX_SIZEOF_X, alors le gcc se plaindra d'une erreur «taille du tableau trop grande». VC ++ émettra soit l'erreur C2148 («la taille totale du tableau ne doit pas dépasser 0x7fffffff octets») soit C4266 «ne peut pas allouer un tableau de taille constante 0».
Les deux définitions sont nécessaires car gcc permettra de définir un tableau de taille zéro de cette façon (sizeof x - n).
la source
L'
sizeof
opérateur n'est pas disponible pour le préprocesseur, mais vous pouvez transférersizeof
vers le compilateur et vérifier la condition à l'exécution:la source
compiler_size
? Qu'est-ce que votre exemple essaie de montrer?