2011-09-24 28 views
7

¿Es posible definir una macro fuera del contenido de una macro?Definir una macro fuera del contenido de una macro

Por ejemplo:

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

SET(myKey,"value") 

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

resultaría en

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

después de haber sido preprocesado.

¿Por qué haría esto? Porque tengo curiosidad;)

+0

Editar su fragmento de modo que tenga la oportunidad de compilar; e intenta compilarlo ¿Lo que pasa? Tengo curiosidad, también. –

+2

@PeteWilson Intentando compilar el código anterior, obtengo 'error: '#' no es seguido por un parámetro macro' como un error – Linsey

+0

+1 por el" ¿por qué haría esto? " :-) –

Respuesta

5

No, no es posible definir una macro dentro de otra macro.

2

El preprocesador solo itera una vez antes del compilador. Lo que está sugiriendo requeriría una cantidad indeterminada de iteraciones.

+0

El preprocesador no determina las macros simplemente una vez. El preprocesador le permite macros # undef' y '# define' varias veces. Cambia y edita las macros a lo largo del proceso, nada evitaría que edite estas reglas dentro de las macros. – Linsey

+0

Lo que hace el preprocesador es "revisar todos los archivos y reemplazar algunas cadenas" en algún orden. El hecho de que haya una orden le permite tener memoria y #undef #ifdef, etc. Sin embargo, para obtener la cadena reemplazada como una macro, se requerirá la recursión. – Willy

+0

podría dar un ejemplo. Estoy de acuerdo en que se requerirá recursividad si quiere reemplazar el texto que precede al '# define' interno, pero si el código entró en vigencia desde el punto en adelante, no parece haber un problema. – Linsey

0

Las macros son una simple sustitución de texto. Generar nuevas directivas de preprocesador a partir de una macro requeriría que el preprocesador continúe el preprocesamiento desde el comenzando con el de la sustitución. Sin embargo, el preprocesamiento definido estándar para continuar detrás de la sustitución.

Esto tiene sentido desde un punto de vista streaming, ver el código sin procesar como el flujo de entrada y el código de procesado (y sustituido) como el flujo de salida. sustituciones de macro pueden tener una longitud arbitraria, lo que significa para el preprocesamiento desde el principio que un número arbitrario de caracteres se debe insertar en el comienzo de la secuencia de entrada para ser procesada de nuevo.

Cuando el procesamiento continúa detrás de la sustitución, la entrada simplemente se maneja en una sola ejecución sin ninguna inserción o almacenamiento en búfer, porque todo va directamente a la salida.

0

Mientras que no es posible usar una macro para definir otra macro, dependiendo de lo que se busca lograr, puede usar macros para lograr efectivamente lo mismo haciendo que definan constantes. por ejemplo, tengo una amplia biblioteca de macros c que utilizo para definir cadenas constantes C y valores clave.

aquí hay algunos fragmentos de código de algunos de mis encabezados.

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

y un ejemplo de uso que lo 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); 

la última parte puede ser un poco difícil de conseguir su cabeza alrededor. los sw_Logging_defineKeys() macro define una lista que lleva el nombre de un macro, ya que es el parámetro (defineKeyValue) este se utiliza entonces para invocar la macro que hace el proceso de definición real. es decir, para cada elemento de la lista, el nombre de macro pasado se utiliza para definir el contexto ("encabezado" o "implementación", por ejemplo, archivo "h" o "m", si comprende las extensiones de archivo objetivo c) mientras que esto se usa para el objetivo c, simplemente se trata de simples macros de c antiguos, usados ​​para un "propósito más elevado" que posiblemente Kernighan and Richie alguna vez previsto. :-)

1

No, no puede - # en una lista de reemplazo de una macro significa QUOTE NEXT TOKEN.Es más un problema de ortografía que cualquier acertijo lógico :)

(Si necesita este tipo de solución en su código, existen formas y trucos de usar macros, pero debe ser específico sobre los casos de uso que necesidad - como su ejemplo se puede lograr mediante la definición: #define mykey "valor")

Aquí se trata de la norma 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.

Cuestiones relacionadas