2010-06-13 15 views
7

Heads up: C'est une question étrange.Extension de macro conditionnelle

J'ai quelques macros très utiles que j'aime utiliser pour simplifier la journalisation. Par exemple je peux faire Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3"), et cela se développera dans une invocation de méthode plus complexe qui inclut des choses comme self, _cmd, __FILE__, __LINE__, etc, de sorte que je peux facilement suivre où les choses sont enregistrées. Cela fonctionne très bien.

Maintenant, je voudrais développer mes macros pour non seulement travailler avec les méthodes Objective-C, mais les fonctions générales C. Le problème est les portions self et _cmd qui sont dans la macro-expansion. Ces deux paramètres n'existent pas dans les fonctions C. Idéalement, j'aimerais pouvoir utiliser ce même ensemble de macros dans les fonctions C, mais je rencontre des problèmes. Lorsque j'utilise (par exemple) ma macro Log(), j'obtiens des avertissements de compilation à propos de self et _cmd qui ne sont pas déclarés (ce qui est tout à fait logique).

Ma première pensée était de faire quelque chose comme ce qui suit (dans ma macro):

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

Ce produit encore des avertissements du compilateur, puisque est substitué en place toute l'instruction if() de la macro, ce qui des erreurs avec les mots-clés self et _cmd (même s'ils ne seront jamais exécutés pendant l'exécution de la fonction).

Ma pensée suivante était de faire quelque chose comme ça (dans ma macro):

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

qui ne fonctionne pas, malheureusement. Je reçois "erreur:" # "n'est pas suivi d'un paramètre macro" sur mon premier #define.

Mon autre pensée était de créer un deuxième ensemble de macros, spécifiquement pour une utilisation dans les fonctions C. Cela sent une mauvaise odeur de code, et je ne veux vraiment pas faire cela. Y at-il un moyen d'utiliser le même ensemble de macros à l'intérieur des méthodes Objective-C et des fonctions C, et seulement référence self et _cmd si la macro est dans une méthode Objective-C?

modifier plus d'informations:

thisFunctionIsACFunction est déterminée d'une manière assez rudimentaire (et je suis certainement ouvert à des améliorations et suggestions). Fondamentalement, il est ceci:

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

Il est reposant sur le comportement du compilateur préfixer un « - » ou « + » par exemple et les méthodes de classe sur les objets Objective-C. Tout le reste doit être une fonction C (puisque les fonctions C ne peuvent pas avoir de noms commençant par '-' ou '+'). Je comprends que cette vérification est techniquement un contrôle d'exécution, puisque __PRETTY_FUNCTION__ est remplacé par un char*, et c'est probablement le principal obstacle à ma demande d'aide.

+0

Comment venez-vous avec 'thisFunctionIsACFunction'? – Artelius

+0

@Artelius question éditée avec plus d'informations –

Répondre

7

Le préprocesseur fait tout son travail avant que le code réel soit analysé. Le préprocesseur ne peut pas savoir si une fonction est C ou obj-C car elle s'exécute avant que le code ne soit analysé.

Pour la même raison,

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

ne peut pas travailler - les #defines sont traités avant la phase de compilation. Par conséquent, le code lui-même doit contenir une vérification "runtime" (bien que le compilateur puisse optimiser cela).

Je suggère de définir quelque chose comme

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

à portée mondiale; les fonctions C "verront" ces définitions tandis que les méthodes Objective-C les cacheront avec leurs propres définitions.

+0

+1 Ha! Tu es un génie! Je n'aurais jamais pensé à définir 'self' et' _cmd' au niveau global! Merci! (Et ça fonctionne parfaitement, je l'ai juste essayé.) –

0

Vous pouvez utiliser une sorte de macro conditionnelle:

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

Je ne suis pas tout à fait sûr de ce que vous devez définir self et _cmd, ceux étaient juste devine. Je ne suis pas sûr s'il existe une macro prédéfinie que vous pouvez vérifier si vous compilez en Objective C, donc vous devrez peut-être définir manuellement OBJECTIVE_C dans le cadre de votre construction.

+0

Bonne idée. Le seul problème est que Objective-C est un sur-ensemble strict de C, ce qui signifie que ObjC et C peuvent coexister pacifiquement côte à côte. Cela signifie que la plupart de mes fonctions C auront '__OBJC__' # define'd. –

1

Vous pouvez utiliser

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