2009-11-25 4 views
17

J'essaie de faire quelque chose de vraiment trivial: Une macro qui prend une chaîne et l'imprime à NSLog.Comment faire une macro qui peut prendre une chaîne?

Comme ceci:

#define PRINTTHIS(text) \ 
    NSLog(@"text"); 

Cependant, lorsque je tente de transmettre une chaîne à ce type je finis par obtenir « texte » imprimé à la console. Toutes les variables ne sont-elles pas remplacées au niveau de la chaîne dans la macro? Comment faire ça bien?

+1

peut-être vous voulez rechercher NSLog () en référence pour voir comment l'utiliser? – stefanB

+0

Comme d'autres l'ont souligné, il semble que vous vouliez la syntaxe "curing" "stringizing": Voir http://en.wikipedia.org/wiki/C_preprocessor#Quoting_macro_arguments –

Répondre

12

Vous voulez utiliser l'opérateur « stringizing » de préprocesseur, #, et probablement l'opérateur « coller jeton », « ## »:

#define STRINGIFY2(x) #x 
#define STRINGIFY(x) STRINGIFY2(x) 
#define PASTE2(a, b) a##b 
#define PASTE(a, b) PASTE2(a, b) 

#define PRINTTHIS(text) \ 
    NSLog(PASTE(@, STRINGIFY(text))); 

Je ne suis pas sûr si besoin Objective-C le '@' ne doit pas avoir d'espace entre le guillemet d'ouverture et le guillemet - si les espaces sont autorisés, supprimez l'opération PASTE().

Notez que vous aurez besoin des niveaux d'indirection goofy 2 pour STRINGIFY() et PASTE() pour fonctionner correctement avec les paramètres de macro. Et cela ne fait presque jamais mal à moins que vous ne fassiez quelque chose de très inhabituel (où vous ne voulez pas que les paramètres de macro soient étendus), il est donc assez courant d'utiliser ces opérateurs de cette manière.

3

Je pense que le problème que vous rencontrez est que "texte" est à l'intérieur de ce qui apparaît au préprocesseur comme un littéral de chaîne (les guillemets, et éventuellement le symbole @), donc il ne remplace pas. Juste une supposition, mais cela fonctionnerait-il?

#define PRINTTHIS(text) \ 
    NSLog(@"%@", text); 

PRINTTHIS(@"string");

Vous pouvez également définir une version qui prend des chaînes C au lieu de chaînes ObjC:

#define PRINTTHIS_C(text) \ 
    NSLog(@"%s", text); 

PRINTTHIS_C("string");
+0

De la façon dont il l'a écrit, il semble qu'il veut écrire PRINTTHIS (Bonjour tout le monde) et faites-le faire NSLog (@ "Hello World"). – Chuck

+1

@Chuck: Oui, mais ça va flipper s'il a un '%' dans la chaîne. – Wevah

0

prendre avec un grain de sel ... Je ne suis pas un développeur Objective-C. Mais dans les macros de type C, les paramètres de macro apparaissant à l'intérieur des littéraux de chaîne ne sont pas remplacés par leurs arguments réels correspondants, donc la substitution que vous essayez de faire ne fonctionnera pas.

Cela pourrait fonctionner:

#define PRINTTHIS(text) \ 
    NSLog(@text); 

PRINTTHIS("your message here"); 

(de sorte que les guillemets sont déplacés hors de la définition de la macro.)

Chuck souligne dans un commentaire que Objective-C, le @ est considéré comme faisant partie le jeton dans cette construction. Il pourrait donc être nécessaire d'utiliser l'opérateur de coller jeton ##:

#define PRINTTHIS(text) \ 
     NSLog(@##text); 
+1

Le préprocesseur Objective-C fonctionne exactement de la même manière, sauf que le @ fait partie du jeton (il spécifie un littéral NSString, par opposition à "", qui spécifie un littéral de chaîne de caractères). Vous avez raison à propos de la raison. – Chuck

+0

Merci Chuck! J'ai mis à jour ma réponse Espérons que cela fera pointer la direction dans la bonne direction. –

9

Voici une façon d'écrire une macro qui colle son argument textuellement dans un objet chaîne, mais il me semble un peu noueux:

#define PRINTTHIS(text) NSLog((NSString *)CFSTR(#text)) 

Il utilise l'opérateur de chaînage pour transformer l'argument en une chaîne C, qu'il utilise ensuite pour créer une chaîne CFS, qui est pontée avec NSString.

4

Utilisez

#define PRINTTHIS(text) \ 
    do { NSLog(@"%s", #text); } while(0) 

De cette façon, le texte peut contenir des caractères%, son 'si l'épreuve', les points-virgules sont tous au bon endroit, etc ...Personnellement, cependant, je dirais qu'il est plus logique d'utiliser directement NSLog().

+0

Cela va imprimer n'importe quelle expression que vous passez à la macro. Si vous passez '[foo objectAtIndex: idx]', il affichera "[foo objectAtIndex: idx]". En supposant que le questionneur veut réellement imprimer la chaîne, il doit omettre l'opérateur # et peut vouloir utiliser '% @' au lieu de '% s' (selon le type de chaîne). –

7

Il semble que cela fonctionnerait aussi bien.

#define PRINTTHIS(text) NSLog(@#text); 

Juste testé, et il semble fonctionner très bien.

+0

Il peut aussi s'agir de ce NSLog (@ # text "quelque chose en annexe"); – malhal

0

Je crois que c'est juste une question de prudence avec les espaces. Cela devrait bien:

#define PRINTTEXT(msg) NSLog((msg))

Un autre exemple:

#define TFCheckPoint(msg) [TestFlight passCheckpoint: (msg) ];

0

Je suis sous l'impression que c'est ce que vous voulez dire, et que vous voulez

Vous voulez une chaîne qui peut prendre un argument, tout en contenant d'autres chaînes, quelque chose de similaire à une fonction stringwithformat.

#define ThisMacro(value) @"Hello my name is %@, and I'm a developer", value 

ensuite utiliser la macro que vous passez juste la valeur à laquelle il ajoute à la chaîne complète

NSLog(ThisMacro(@"Mthokozisi")) 

Le résultat final sera, @"Hello my name is Mthokozisi, and I'm a developer"

Questions connexes