2011-09-24 17 views
7

È possibile definire una macro fuori dal contenuto di una macro?Definire una macro dal contenuto di una macro

Ad esempio:

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

SET(myKey,"value") 

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

comporterebbe

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

dopo essere pre-elaborato.

Perché dovrei farlo? Perché sono curioso;)

+0

Modificare il frammento in modo che abbia la possibilità di compilazione; e prova a compilarlo. Che succede? Anch'io sono curioso. –

+2

@PeteWilson Tentativo di compilare il codice sopra, ottengo 'errore: '#' non è seguito da un parametro macro' come errore – Linsey

+0

+1 per" perché dovrei farlo? " :-) –

risposta

5

No, non è possibile definire una macro all'interno di un'altra macro.

2

Il preprocessore esegue una sola iterazione una sola volta prima del compilatore. Quello che stai suggerendo richiederebbe una quantità indeterminata di iterazioni.

+0

Il preprocessore non determina le macro semplicemente una volta. Il preprocessore consente di # undef' e '# define' macro più volte. Cambia e modifica i macro durante l'elaborazione, nulla impedirebbe di modificare queste regole all'interno delle macro. – Linsey

+0

Quello che fa il preprocessore è "andare su tutti i file e sostituire alcune stringhe" in qualche ordine. Il fatto che ci sia un ordine permette di avere memoria e #undef #ifdef ecc ... Tuttavia per ottenere la stringa sostituita come una macro richiederebbe la ricorsione. – Willy

+0

potresti fornire un esempio. Sono d'accordo che la ricorsione sarebbe necessaria se si volesse sostituire il testo che precede il '# define interno, ma se il codice ha avuto effetto dal punto in cui appare non sembra essere un problema. – Linsey

0

Le macro sono una semplice sostituzione di testo. La generazione di nuove direttive del preprocessore da una macro richiederebbe al preprocessore di continuare la preelaborazione da all'inizio di della sostituzione. Tuttavia, il preprocessing definito dallo standard per continuare dietro la sostituzione.

Questo ha senso dal punto di vista dello streaming, visualizzando il codice non elaborato come il flusso di input e il codice elaborato (e sostituito) come il flusso di output. Le sostituzioni di macro possono avere una lunghezza arbitraria, il che significa per il preprocessore dall'inizio che un numero arbitrario di caratteri deve essere inserito all'inizio del flusso di input per essere elaborato nuovamente.

Quando l'elaborazione continua dietro la sostituzione, l'input viene semplicemente gestito in una sola esecuzione senza alcun inserimento o buffering, poiché tutto va direttamente all'output.

0

mentre non è possibile utilizzare una macro per definire un'altra macro, a seconda di ciò che si sta cercando di ottenere, è possibile utilizzare le macro per ottenere effettivamente la stessa cosa facendole definire costanti. per esempio, ho una vasta libreria di macro c che uso per definire stringhe costanti oggettive C e valori chiave.

Ecco alcuni frammenti di codice di alcune delle mie intestazioni.

// 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__) 

e un esempio di utilizzo che invoca:

#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); 

l'ultima parte può essere un po 'difficile da ottenere la testa intorno. la macro sw_Logging_defineKeys() definisce un elenco che prende il nome di una macro come parametro (defineKeyValue), quindi viene utilizzato per richiamare la macro che esegue il processo di definizione effettivo. cioè, per ogni elemento nell'elenco, il nome della macro passato viene utilizzato per definire il contesto ("intestazione" o "implementazione", ad esempio il file "h" o "m", se si comprendono le estensioni di file obiettivo c) mentre questo è usato per l'obiettivo c, è semplicemente semplice macro c vecchio, usato per uno "scopo più alto" del possibile Kernighan and Richie mai immaginato. :-)

1

No, non è possibile - # in un elenco di sostituzione di una macro significa QUOTE NEXT TOKEN.È più un problema di ortografia, che qualsiasi puzzle logico :)

(Se hai bisogno di questo tipo di soluzione nel tuo codice, ci sono modi e trucchi per usare le macro, ma devi essere specifico riguardo ai casi d'uso necessità - come il vostro esempio può essere raggiunto attraverso la definizione: #define MyKey "valore")

Eccolo dallo standard 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.

Problemi correlati