C-Makros zum Erstellen von Zeichenfolgen

Lesezeit: 6 Minuten

Benutzer-Avatar
Richard Stelling

Alternative Titel (um die Suche zu erleichtern)

  • Konvertieren Sie ein Präprozessor-Token in eine Zeichenfolge
  • Wie erstelle ich eine Zeichenkette aus a C Wert des Makros?

Ursprüngliche Frage

Ich möchte verwenden C #define wörtliche Zeichenfolgen zur Kompilierzeit zu erstellen.

Die Zeichenfolge sind Domänen, die sich für Debug, Release usw. ändern.

Ich hätte gerne etwas in der Art:

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

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

Aber der Präprozessor wertet nichts innerhalb von “” aus

  1. Gibt es eine Möglichkeit, dies zu umgehen?
  2. Ist das überhaupt eine gute Idee?

  • Mögliches Duplikat von Convert a preprocessor token to a string

    – Ciro Santilli OurBigBook.com

    5. Oktober 2015 um 13:33 Uhr

Benutzer-Avatar
Alex B

In C werden String-Literale automatisch verkettet. Zum Beispiel,

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

s1 und s2 sind die gleiche Saite.

Für Ihr Problem lautet die Antwort (ohne Token-Einfügen).

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

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

Benutzer-Avatar
Michael Burr

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

  1. Wenn Sie nur mit Zeichenfolgenliteralen arbeiten, können Sie einfach Zeichenfolgen verwenden. Wenn Sie ein Zeichenfolgenliteral nach dem anderen platzieren, werden sie vom Compiler verkettet.

  2. Wenn andere Dinge als String-Literale beteiligt sind (dh Sie erstellen neue Bezeichner aus den Makros), verwenden Sie das ‘##” Präprozessor-Token-Einfügeoperator. Sie müssten wahrscheinlich auch den ‘#‘ ‘Stringisierungsoperator, um Ihre Makros in wörtliche Strings umzuwandeln.

Ein Beispiel für #1:

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

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

Und was den Operator zum Einfügen von Token betrifft, glaube ich nicht, dass die meisten Antworten, die die Verwendung des Präprozessoroperators zum Einfügen von Token vorgeschlagen haben, ihn tatsächlich ausprobiert haben – er kann schwierig zu verwenden sein.

Die Verwendung der häufig vorgeschlagenen Antwort führt zu einem Compilerfehler, wenn Sie versuchen, die zu verwenden IV_SECURE Makro, weil:

#define IV_SECURE "secure."##IV_DOMAIN

erweitert sich zu:

"secure"example.org

Vielleicht möchten Sie versuchen, die zu verwenden '#`’ ‘Stringing’-Operator:

#define IV_SECURE "secure." #IV_DOMAIN

Aber das wird nicht funktionieren, weil es nur mit Makroargumenten funktioniert – nicht mit irgendeinem alten Makro.

Eine Sache, die Sie beachten sollten, wenn Sie die Vorverarbeitungsoperatoren zum Einfügen von Token (‘##’) oder Zeichenfolgen (‘#’) verwenden, ist, dass Sie eine zusätzliche Indirektionsebene verwenden müssen, damit sie in allen Fällen richtig funktionieren.

Wenn Sie dies nicht tun und die an den Operator zum Einfügen von Token übergebenen Elemente selbst Makros sind, erhalten Sie Ergebnisse, die wahrscheinlich nicht Ihren Wünschen entsprechen:

#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__)));
}

Die Ausgabe:

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

desired result:
function_name21

Verwenden Sie also Ihr Original IV_DOMAIN definiert und die Utility-Makros von oben, könnten Sie dies tun, um zu bekommen, was Sie wollen:

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

Benutzer-Avatar
rpetrich

Die nächsten Zeichenfolgen werden vom C-Compiler kombiniert.

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

Ich sehe viele gute und richtige Antworten auf Ihre erste Frage, aber keine auf Ihre zweite, also hier ist dies: Ich denke, das ist eine schreckliche Idee. Warum sollten Sie Ihre Software (insbesondere die Release-Version) neu erstellen müssen, nur um den Servernamen zu ändern? Und woher wissen Sie, welche Version Ihrer Software auf welchen Server verweist? Sie müssen einen Mechanismus einbauen, um zur Laufzeit zu überprüfen. Wenn es auf Ihrer Plattform überhaupt praktikabel ist, empfehle ich Ihnen, die Domains/URLs aus einer Konfigurationsdatei zu laden. Nur die kleinste eingebettete Plattform ist für diesen Zweck möglicherweise nicht “praktisch” 🙂

Versuchen Sie es mit dem ##-Operator

#define IV_SECURE secure.##IV_DOMAIN

  • Ich denke, das OP hat nach der Zeichenfolgenverkettung (#) gefragt, nicht nach dem Einfügen von Token (##). Ich habe jedoch nicht abgelehnt. Die Frage ist etwas zweideutig.

    – e.James

    28. April 2009 um 14:38 Uhr

  • Das Einfügen von Tokens (‘##’) oder Strings (‘#’) funktioniert nicht ohne einiges an zusätzlichem Zeug.

    – Michael Burr

    28. April 2009 um 15:01 Uhr

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

Der Vorverarbeitungsoperator # verwandelt den Makroparameter in einen String. 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

was IV_SECURE zu ändern sollte

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

die automatisch zu “secure.domain.org” verkettet wird (vorausgesetzt, die Übersetzungsphasen sind in C dieselben wie in C++).

ANDERE BEARBEITUNG: Bitte lesen Sie die Kommentare, die zeigen, wie ich es geschafft habe, verwirrt zu werden. Denken Sie daran, dass ich gründliche Erfahrung in C habe, wenn auch vielleicht ein wenig eingerostet. Ich würde diese Antwort löschen, aber ich dachte, ich würde sie als Beispiel dafür belassen, wie leicht es ist, vom C-Präprozessor verwirrt zu werden.

  • Ich denke, das OP hat nach der Zeichenfolgenverkettung (#) gefragt, nicht nach dem Einfügen von Token (##). Ich habe jedoch nicht abgelehnt. Die Frage ist etwas zweideutig.

    – e.James

    28. April 2009 um 14:38 Uhr

  • Das Einfügen von Tokens (‘##’) oder Strings (‘#’) funktioniert nicht ohne einiges an zusätzlichem Zeug.

    – Michael Burr

    28. April 2009 um 15:01 Uhr

Verwenden Sie, wie andere angemerkt haben, das Einfügen von Token. Sie sollten sich auch darüber im Klaren sein, dass Makronamen wie

__TESTING

sind in C (keine Ahnung von Objective C) für die Implementierung reserviert – Sie dürfen sie nicht in Ihrem eigenen Code verwenden. Die reservierten Namen sind alles, was doppelte Unterstriche enthält und alles, was mit einem Unterstrich und einem Großbuchstaben beginnt.

  • Ziel C soll eine strenge Obermenge von C sein, und daher sollte dies eine gültige Benachrichtigung sein.

    – Chris Lutz

    28. April 2009 um 14:48 Uhr

1383960cookie-checkC-Makros zum Erstellen von Zeichenfolgen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy