2010-06-13 24 views
7

Heads up: Esta es una pregunta extraña.Expansión de macro condicional

Tengo algunas macros realmente útiles que me gusta usar para simplificar algunos registros. Por ejemplo, puedo hacer Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3"), y eso se ampliará a una invocación de método más complejo que incluye cosas como self, _cmd, __FILE__, __LINE__, etc., de modo que pueda rastrear fácilmente dónde se registran las cosas. Esto funciona genial

Ahora me gustaría expandir mis macros no solo para trabajar con métodos Objective-C, sino también con funciones C generales. El problema son las porciones self y _cmd que se encuentran en la expansión de macros. Estos dos parámetros no existen en las funciones C. Idealmente, me gustaría poder usar este mismo conjunto de macros dentro de las funciones C, pero estoy teniendo problemas. Cuando uso (por ejemplo) mi macro Log(), recibo advertencias del compilador acerca de self y _cmd no declaradas (lo que tiene sentido).

Mi primera idea era hacer algo como lo siguiente (en mi macro):

if (thisFunctionIsACFunction) { 
    DoLogging(nil, nil, format, ##__VA_ARGS__); 
} else { 
    DoLogging(self, _cmd, format, ##__VA_ARGS__); 
} 

Esto todavía produce advertencias del compilador, ya que toda la instrucción if() se sustituye en lugar de la macro, lo que resulta en errores con las palabras clave self y _cmd (aunque nunca se ejecutarán durante la ejecución de la función).

Mi siguiente pensamiento fue a hacer algo como esto (en mi macro):

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

eso no funciona, por desgracia. Me sale "error: '#' no es seguido por un parámetro de macro" en mi primer #define.

Mi otro pensamiento fue crear un segundo conjunto de macros, específicamente para usar en funciones C. Esto apesta a un mal olor de código, y yo realmente no quiero hacer esto.

¿Hay alguna manera en que pueda usar el mismo conjunto de macros desde ambos métodos Objective-C y C, y solo haga referencia a self y _cmd si la macro está en un método Objective-C?

edición más información:

thisFunctionIsACFunction se determina de una manera bastante rudimentario (y yo soy definitivamente abierto a mejoras y sugerencias). Básicamente se trata de esto:

BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+'); 

Está confiando en el comportamiento del compilador para anteponer un '-' o '+' para la instancia y métodos de la clase de objetos Objective-C. Cualquier otra cosa debe ser una función C (ya que las funciones C no pueden tener nombres que comiencen con '-' o '+').

Entiendo que este control es técnicamente un control en tiempo de ejecución, ya que __PRETTY_FUNCTION__ se reemplaza con char*, y este es probablemente el principal obstáculo para mi solicitud de ayuda.

+0

¿Cómo se te ocurrió con 'thisFunctionIsACFunction'? – Artelius

+0

@Artelius editó la pregunta con más información –

Respuesta

7

El preprocesador hace todo su trabajo antes de analizar el código real. El preprocesador no puede saber si una función es C u obj-C porque se ejecuta antes de que se analice el código.

Por la misma razón,

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

no puede trabajar - los #defines se procesan antes de la etapa de compilación.

Por lo tanto, el código en sí debe contener una verificación de "tiempo de ejecución" (aunque el compilador puede optimizar esto).

Yo sugeriría que define algo como

void *self = nil; //not sure about the types that 
SEL _cmd = nil; //would be valid for obj-c 

en el ámbito mundial; las funciones C "verán" estas definiciones, mientras que los métodos Objective-C las esconderán con sus propias definiciones.

+0

+1 Ha! ¡Eres un genio! ¡Nunca hubiera pensado en definir 'self' y' _cmd' a nivel global! ¡Gracias! (Y funciona perfectamente; lo probé) –

0

Usted puede utilizar algún tipo de macro condicional:

#ifndef OBJECTIVE_C 
    #define self 0 
    #define _cmd "" 
#endif 

No estoy muy seguro de lo que debe definir self y _cmd a, aquellos eran sólo conjeturas.

No estoy seguro de si hay una macro predefinida que pueda verificar si está compilando en el Objetivo C, por lo que puede necesitar definir OBJECTIVE_C manualmente como parte de su compilación.

+0

Buena idea. El único problema es que Objective-C es un superconjunto estricto de C, lo que significa que ObjC y C pueden coexistir pacíficamente uno al lado del otro. Esto significa que la mayoría de mis funciones C tendrán '__OBJC__' # defined'd. –

1

Puede utilizar

if defined "abc" <statement1> 
else if defined "def" <statement2> 
Cuestiones relacionadas