2011-09-24 8 views
7

Est-il possible de définir une macro à partir du contenu d'une macro?Définir une macro sur le contenu d'une macro

Par exemple:

#define SET(key,value) #define key value 

SET(myKey,"value") 

int main(){ 
    char str[] = myKey; 
    printf("%s",str); 
} 

entraînerait

int main(){ 
    char str[] = "value"; 
    printf("%s",str); 
} 

après avoir été prétraité.

Pourquoi le ferais-je? Parce que je suis curieux;)

+0

Modifier votre fragment il a une chance de compilation; et essayez de le compiler. Ce qui se produit? Je suis curieux aussi. –

+2

@PeteWilson Tentative de compiler le code ci-dessus, j'obtiens 'error: '#' n'est pas suivi d'un macro paramètre' comme une erreur – Linsey

+0

+1 pour le" pourquoi je le ferais? " :-) –

Répondre

5

Non, il n'est pas possible de définir une macro dans une autre macro.

2

Le préprocesseur ne se répète qu'une fois avant le compilateur. Ce que vous suggérez nécessiterait une quantité indéterminée d'itérations.

+0

Le préprocesseur ne détermine pas les macros simplement une fois. Le préprocesseur vous permet d'exécuter plusieurs fois les macros #defin et # define. Il modifie et édite les macros tout au long du traitement, rien ne l'empêcherait d'éditer ces règles à l'intérieur des macros. – Linsey

+0

Ce que fait le préprocesseur est "parcourir tous les fichiers et remplacer certaines chaînes" dans un certain ordre. Le fait qu'il y ait un ordre lui permet d'avoir de la mémoire et #undef #ifdef etc ... Cependant, pour obtenir la chaîne remplacée en tant que macro, il faudrait récursion. – Willy

+0

pourriez-vous s'il vous plaît fournir un exemple. Je suis d'accord que la récursion serait nécessaire si vous vouliez remplacer le texte précédant l'intérieur '# define', mais si le code a pris effet à partir du point, il ne semble pas y avoir de problème. – Linsey

0

Les macros sont une simple substitution de texte. La génération de nouvelles directives de préprocesseur à partir d'une macro nécessiterait que le préprocesseur poursuive le prétraitement à partir du commençant de la substitution. Cependant, le prétraitement standard défini pour continuer derrière la substitution.

Cela a du sens d'un point de vue de la lecture en continu, en considérant le code non traité comme le flux d'entrée et le code traité (et substitué) comme le flux de sortie. Les substitutions de macros peuvent avoir une longueur arbitraire, ce qui signifie pour le prétraitement depuis le début qu'un nombre arbitraire de caractères doit être inséré au début du flux d'entrée pour être traité à nouveau. Lorsque le traitement se poursuit derrière la substitution, l'entrée est simplement traitée en une seule opération sans aucune insertion ou mise en mémoire tampon, car tout va directement à la sortie.

0

Bien qu'il ne soit pas possible d'utiliser une macro pour définir une autre macro, en fonction de ce que vous cherchez à obtenir, vous pouvez utiliser des macros pour obtenir la même chose en définissant des constantes. Par exemple, j'ai une vaste bibliothèque de macros c que j'utilise pour définir les chaînes constantes de l'objectif C et les valeurs clés.

Voici quelques extraits de code de certains de mes en-têtes.

// use defineStringsIn_X_File to define a NSString constant to a literal value. 
// usage (direct) : defineStringsIn_X_File(constname,value); 

#define defineStringsIn_h_File(constname,value) extern NSString * const constname; 
#define defineStringsIn_m_File(constname,value) NSString * const constname = value; 


// use defineKeysIn_X_File when the value is the same as the key. 
// eg myKeyname has the value @"myKeyname" 
// usage (direct) : defineKeysIn_X_File(keyname); 
// usage (indirect) : myKeyDefiner(defineKeysIn_X_File); 
#define defineKeysIn_h_File(key) defineStringsIn_h_File(key,key) 
#define defineKeysIn_m_File(key) defineStringsIn_m_File(key,@#key) 



// use defineKeyValuesIn_X_File when the value is completely unrelated to the key - ie you supply a quoted value. 
// eg myKeyname has the value @"keyvalue" 
// usage: defineKeyValuesIn_X_File(keyname,@"keyvalue"); 
// usage (indirect) : myKeyDefiner(defineKeyValuesIn_X_File); 
#define defineKeyValuesIn_h_File(key,value) defineStringsIn_h_File(key,value) 
#define defineKeyValuesIn_m_File(key,value) defineStringsIn_m_File(key,value) 



// use definePrefixedKeys_in_X_File when the last part of the keyname is the same as the value. 
// eg myPrefixed_keyname has the value @"keyname" 
// usage (direct) : definePrefixedKeys_in_X_File(prefix_,keyname); 
// usage (indirect) : myKeyDefiner(definePrefixedKeys_in_X_File); 

#define definePrefixedKeys_in_h_File_2(prefix,key) defineKeyValuesIn_h_File(prefix##key,@#key) 
#define definePrefixedKeys_in_m_File_2(prefix,key) defineKeyValuesIn_m_File(prefix##key,@#key) 

#define definePrefixedKeys_in_h_File_3(prefix,key,NSObject) definePrefixedKeys_in_h_File_2(prefix,key) 
#define definePrefixedKeys_in_m_File_3(prefix,key,NSObject) definePrefixedKeys_in_m_File_2(prefix,key) 

#define definePrefixedKeys_in_h_File(...) VARARG(definePrefixedKeys_in_h_File_, __VA_ARGS__) 
#define definePrefixedKeys_in_m_File(...) VARARG(definePrefixedKeys_in_m_File_, __VA_ARGS__) 




// use definePrefixedKeyValues_in_X_File when the value has no relation to the keyname, but the keyname has a common prefixe 
// eg myPrefixed_keyname has the value @"bollocks" 
// usage: definePrefixedKeyValues_in_X_File(prefix_,keyname,@"bollocks"); 
// usage (indirect) : myKeyDefiner(definePrefixedKeyValues_in_X_File); 
#define definePrefixedKeyValues_in_h_File(prefix,key,value) defineKeyValuesIn_h_File(prefix##key,value) 
#define definePrefixedKeyValues_in_m_File(prefix,key,value) defineKeyValuesIn_m_File(prefix##key,value) 







#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N 
#define VA_NARGS(...) VA_NARGS_IMPL(X,##__VA_ARGS__, 11, 10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 
#define VARARG_IMPL2(base, count, ...) base##count(__VA_ARGS__) 
#define VARARG_IMPL(base, count, ...) VARARG_IMPL2(base, count, __VA_ARGS__) 
#define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__) 

et un exemple d'utilisation qui l'invoque:

#define sw_Logging_defineKeys(defineKeyValue) \ 
/** start of key list for sw_Logging_ **/\ 
/**/defineKeyValue(sw_Logging_,log)\ 
/**/defineKeyValue(sw_Logging_,time)\ 
/**/defineKeyValue(sw_Logging_,message)\ 
/**/defineKeyValue(sw_Logging_,object)\ 
/**/defineKeyValue(sw_Logging_,findCallStack)\ 
/**/defineKeyValue(sw_Logging_,debugging)\ 
/**/defineKeyValue(sw_Logging_,callStackSymbols)\ 
/**/defineKeyValue(sw_Logging_,callStackReturnAddresses)\ 
/** end of key list for sw_Logging_ **/ 
sw_Logging_defineKeys(definePrefixedKeys_in_h_File); 

la dernière partie peut être un peu difficile d'obtenir autour de votre tête. La macro sw_Logging_defineKeys() définit une liste qui prend le nom d'une macro en tant que paramètre (defineKeyValue). Elle est ensuite utilisée pour invoquer la macro qui exécute le processus de définition. Par exemple, pour chaque élément de la liste, le nom de macro transmis est utilisé pour définir le contexte ("en-tête" ou "implémentation", par exemple "h" ou "m", si vous comprenez les extensions de fichier c objectives) alors que ceci est utilisé pour l'objectif c, il s'agit tout simplement de vieilles macros c, utilisées pour un "but plus élevé" que possible Kernighan and Richie jamais envisagé. :-)

1

Non, vous ne pouvez pas - # dans une liste de remplacements d'une macro signifie QUOTE NEXT TOKEN.C'est plus un problème d'orthographe que n'importe quel puzzle logique :)

(Si vous avez besoin de ce type de solution dans votre code, il y a des façons et des astuces d'utiliser des macros, mais vous devez être précis sur les cas d'utilisation besoin - que votre exemple peut être réalisé en définissant: #define MyKey « valeur »)

ici, il est de la norme ansi C99

6.10.3.2 The # operator

Constraints

1 Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list. Semantics 2 If, in the replacement list, a parameter is immediately preceded by a # preprocessing token, both are replaced by a single character string literal preprocessing token that contains the spelling of the preprocessing token sequence for the corresponding argument. Each occurrence of white space between the argument’s preprocessing tokens becomes a single space character in the character string literal. White space before the first preprocessing token and after the last preprocessing token composing the argument is deleted. Otherwise, the original spelling of each preprocessing token in the argument is retained in the character string literal, except for special handling for producing the spelling of string literals and character constants: a \ character is inserted before each " and \ character of a character constant or string literal (including the delimiting " characters), except that it is implementation-defined whether a \ character is inserted before the \ character beginning a universal character name. If the replacement that results is not a valid character string literal, the behavior is undefined. The character string literal corresponding to an empty argument is "". The order of evaluation of # and ## operators is unspecified.