2009-04-28 22 views
24

Alternative Titel (helfen Suche)C Makros Strings erstellen

  • Konvertieren ein Präprozessor-Token in einen String
  • Wie ein char String aus einem C Makro Wert machen?

Original Question

Ich mag würde C#define zu bauen Literalzeichenfolgen bei der Kompilierung verwenden.

Die Zeichenfolge sind Domänen, die für Debug-Change-, Release- usw.

ich einige, wie dies einige Sache möchte:

#ifdef __TESTING 
    #define IV_DOMAIN domain.org   //in house testing 
#elif __LIVE_TESTING 
    #define IV_DOMAIN test.domain.com  //live testing servers 
#else 
    #define IV_DOMAIN domain.com   //production 
#endif 

// Sub-Domain 
#define IV_SECURE "secure.IV_DOMAIN"    //secure.domain.org etc 
#define IV_MOBILE "m.IV_DOMAIN" 

Aber der Prä-Prozessor wertet nicht alles innerhalb von „“

  1. Gibt es einen Weg um diese?
  2. Ist das überhaupt eine gute Idee?
+0

Mögliches Duplikat von [Konvertiere ein Präprozessor-Token in einen String] (http://stackoverflow.com/questions/240353/convert-a-preprocessor -token-to-a-string) –

Antwort

31

In C werden Zeichenfolgenliterale automatisch verkettet. Zum Beispiel

const char * s1 = "foo" "bar"; 
const char * s2 = "foobar"; 

s1 und s2 sind der gleiche String.

Also, für Ihr Problem, die Antwort (ohne token einfügen) ist

#ifdef __TESTING 
    #define IV_DOMAIN "domain.org" 
#elif __LIVE_TESTING 
    #define IV_DOMAIN "test.domain.com" 
#else 
    #define IV_DOMAIN "domain.com" 
#endif 

#define IV_SECURE "secure." IV_DOMAIN 
#define IV_MOBILE "m." IV_DOMAIN 
6

versuchen, die ## Operator

#define IV_SECURE secure.##IV_DOMAIN 
+1

Das löst das "" Problem nicht. – mouviciel

+0

Ich denke, das OP fragt nach String-Verkettung (#), nicht Token-Einfügen (##). Ich habe jedoch nicht runtergestimmt. Die Frage ist ein wenig mehrdeutig. –

+0

Token einfügen ('##') oder stringizing ('#') funktioniert nicht ohne eine Menge zusätzlicher Sachen. –

8

Strings, die nebeneinander durch den C-Compiler kombiniert verwenden.

#define DOMAIN "example.com" 
#define SUBDOMAIN "test." DOMAIN 
const char *asCString = SUBDOMAIN; 
NSString *asNSString = @SUBDOMAIN; 
5

Was Sie brauchen, sind die # und ## Operatoren und automatische Stringverkettung.

Der Operator # preprocessing wandelt den Makroparameter in eine Zeichenfolge um. Der Operator ## fügt zwei Token (z. B. Makroparameter) zusammen.

Die Möglichkeit, die mir in den Sinn kommt ist

#define IV_DOMAIN domain.org 
#define IV_SECURE(DOMAIN) "secure." #DOMAIN 

die IV_SECURE zu

#define IV_SECURE "secure." "domain.org" 

die „secure.domain.org“ automatisch verketten ändern sollte (die Phasen der Übersetzung unter der Annahme, sind in C gleich wie C++).

ANDERES EDIT: Bitte, lesen Sie bitte die Kommentare, die zeigen, wie ich es geschafft habe, verwirrt zu werden. Denken Sie daran, dass ich in C gründlich erfahren bin, obwohl vielleicht eine Note rostig. Ich würde diese Antwort löschen, aber ich dachte, ich würde es als ein Beispiel dafür lassen, wie einfach es ist, vom C-Präprozessor verwirrt zu werden.

+0

## fügt keine Zeichenfolgen ein, fügt Token ein. Subtiler, aber wichtiger Unterschied. –

+0

Leider versteht die Version von cpp, die in meiner Cygwin-Box läuft, den # Operator nicht, wie Sie ihn beschreiben. – mouviciel

+0

Der Operator # funktioniert nur bei Makroparametern. I.e. #define IV_SECURE (DOMAIN) "sicher." #DOMAIN Nicht viel Hilfe in diesem Fall. –

3

Wie andere erwähnt haben, Token-Einfügen verwenden. Sie sollten sich auch bewusst sein, dass Makronamen wie

__TESTING 

in C reserviert sind (nicht über Objective C weiß) für die Umsetzung - Sie sind nicht erlaubt, sie in Ihrem eigenen Code zu verwenden. Die reservierten Namen sind alles, was doppelte Unterstriche und alles was mit einem Unterstrich und einem Großbuchstaben beginnt.

+0

Objective C soll eine strenge Obermenge von C sein, und daher sollte dies ein gültiger Hinweis sein. –

19

Es gibt ein paar Möglichkeiten, dies zu tun:

  1. , wenn Sie mit nur Stringliterale zu tun sind, können Sie einfach und unkompliziert Strings verwenden - Platzierung einer Stringliteral nach dem anderen den Compiler bewirkt, dass sie verketten .

  2. , wenn es andere Dinge involviert als Zeichenfolgenliterale sein kann (dh., Sie neue Kennungen von den Makros erstellen) die Verwendung '## "Präprozessor token einfügen Operator. Sie würden wahrscheinlich müssen auch die Verwendung‚#‘ ‚Zeichenfolgen Operator Ihre Makros in Literalzeichenfolgen machen

Ein Beispiel # 1:.

#ifdef __TESTING 
    #define IV_DOMAIN "domain.org"      //in house testing 
#elif __LIVE_TESTING 
    #define IV_DOMAIN "test.domain.com"   //live testing servers 
#else 
    #define IV_DOMAIN "domain.com"      //production 
#endif 

// Sub-Domain 
#define IV_SECURE "secure." IV_DOMAIN   //secure.domain.org etc 
#define IV_MOBILE "m." IV_DOMAIN 

Und so weit das token einfügen Operator geht, ich glaube nicht, dass die meisten der Antworten, die vorschlagen ted mit dem Token-Pasting-Präprozessor-Operator haben es tatsächlich versucht - es kann schwierig zu bedienen sein.

Mit der Antwort, die oft vorgeschlagen wird, in einem Compiler-Fehler führen wird, wenn Sie das IV_SECURE Makro zu verwenden versuchen, denn:

#define IV_SECURE "secure."##IV_DOMAIN 

expandiert nach:

"secure"domain.org 

Sie könnten versuchen wollen die ' # `‘ 'Zeichenfolge' Operator zu verwenden:

#define IV_SECURE "secure." #IV_DOMAIN 

Aber tha t funktioniert nicht, weil es nur für Makroargumente funktioniert - nicht nur für ein altes Makro.

Wenn Sie die Vorverarbeitungsoperatoren token-paste ('##') oder Stringing ('#') verwenden, müssen Sie eine zusätzliche Indirektionsebene verwenden, damit sie ordnungsgemäß funktionieren auf alle Fälle.

Wenn Sie dies nicht tun und die Elemente auf dem Token-Einfügen-Operator übergeben sind Makros selbst, werden Sie Ergebnisse, die wahrscheinlich nicht das, was Sie wollen:

#include <stdio.h> 

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

#define BAD_PASTE(x,y) x##y 
#define BAD_STRINGIFY(x) #x 

#define SOME_MACRO function_name 

int main() 
{ 
    printf("buggy results:\n"); 
    printf("%s\n", STRINGIFY(BAD_PASTE(SOME_MACRO, __LINE__))); 
    printf("%s\n", BAD_STRINGIFY(BAD_PASTE(SOME_MACRO, __LINE__))); 
    printf("%s\n", BAD_STRINGIFY(PASTE(SOME_MACRO, __LINE__))); 

    printf("\n" "desired result:\n"); 
    printf("%s\n", STRINGIFY(PASTE(SOME_MACRO, __LINE__))); 
} 

Der Ausgang:

buggy results: 
SOME_MACRO__LINE__ 
BAD_PASTE(SOME_MACRO, __LINE__) 
PASTE(SOME_MACRO, __LINE__) 

desired result: 
function_name21 

das bekommen, was Sie wollen, Sie könnten also von oben ursprünglichen IV_DOMAIN definiert und die utilty Makros tun:

// Sub-Domain 
#define IV_SECURE "secure." STRINGIFY(IV_DOMAIN) //secure.domain.org etc 
#define IV_MOBILE "m." STRINGIFY(IV_DOMAIN) 
6

Ich sehe viele gute und richtige Antworten auf Ihre erste Frage, aber keine auf Ihre Sekunde, also hier ist das: Ich denke, das ist eine schreckliche Idee. Warum sollten Sie Ihre Software neu erstellen (insbesondere die Release-Version), nur um den Servernamen zu ändern? Wie werden Sie wissen, welche Version Ihrer Software auf welchen Server zeigt? Sie müssen einen Mechanismus einbauen, der zur Laufzeit überprüft. Wenn es auf Ihrer Plattform praktisch ist, empfehle ich Ihnen, die Domains/URLs aus einer Konfigurationsdatei zu laden. Nur die kleinsten eingebetteten Plattformen sind möglicherweise nicht "praktisch" für diesen Zweck :)