Makros zum Erstellen von Strings in C

Lesezeit: 6 Minuten

Benutzeravatar von Richard Stelling
Richard Stelling

Alternative Titel (zur Erleichterung der Suche)

  • Konvertieren Sie ein Präprozessor-Token in eine Zeichenfolge
  • Wie kann ich aus a eine Zeichenfolge erstellen? C Makrowert?

Ursprüngliche Frage

Ich möchte verwenden C #define um Literalzeichenfolgen zur Kompilierungszeit zu erstellen.

Bei der Zeichenfolge handelt es sich um Domänen, die sich zum Debuggen, zur Veröffentlichung usw. ändern.

Ich würde gerne so etwas machen:

#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

// Subdomain
#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 einen Weg, dies zu umgehen?
  2. Ist das überhaupt eine gute Idee?

  • Mögliches Duplikat von Konvertieren eines Präprozessor-Tokens in eine Zeichenfolge

    – Ciro Santilli OurBigBook.com

    5. Okt. 2015 um 13:33

Benutzeravatar von Alex B
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 Zeichenfolge.

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 von Michael Burr
Michael Burr

Es gibt mehrere Möglichkeiten, dies zu tun:

  1. Wenn Sie nur mit String-Literalen arbeiten, können Sie einfach Strings verwenden. Wenn Sie ein String-Literal nach dem anderen platzieren, verkettet der Compiler diese.

  2. Wenn möglicherweise andere Dinge als String-Literale beteiligt sind (z. B. wenn Sie neue Bezeichner aus den Makros erstellen), verwenden Sie die Option „##“Operator zum Einfügen von Präprozessor-Tokens. Sie müssten wahrscheinlich auch den ‘#‘ ‘Stringisierungsoperator, um Ihre Makros in Literalzeichenfolgen 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

// Subdomain
#define IV_SECURE "secure." IV_DOMAIN          // secure.example.org, etc.
#define IV_MOBILE "m." IV_DOMAIN

Und was den Token-Paste-Operator betrifft, glaube ich nicht, dass die meisten Antworten, die die Verwendung des Token-Paste-Präprozessoroperators vorgeschlagen haben, ihn tatsächlich ausprobiert haben – die Verwendung kann schwierig 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, das zu verwenden '#`’ ‘Stringisierungs’-Operator:

#define IV_SECURE "secure." #IV_DOMAIN

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

Wenn Sie die Vorverarbeitungsoperatoren token-paste (‘##’) oder stringizing (‘#’) verwenden, sollten Sie sich darüber im Klaren sein, dass Sie eine zusätzliche Indirektionsebene verwenden müssen, damit sie in allen Fällen ordnungsgemäß funktionieren.

Wenn Sie dies nicht tun und die an den Token-Einfüge-Operator ü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 Dienstprogrammmakros von oben, können Sie Folgendes tun, um das zu bekommen, was Sie wollen:

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

Benutzeravatar von rpetrich
rpetrich

Nachfolgende Zeichenfolgen werden vom C-Compiler kombiniert.

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

Benutzeravatar von rmeador
rmeador

Ich sehe viele gute und richtige Antworten auf Ihre erste Frage, aber keine auf Ihre zweite. Deshalb hier: Ich halte das für 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 zur Überprüfung zur Laufzeit einbauen.

Wenn es auf Ihrer Plattform überhaupt praktikabel ist, empfehle ich Ihnen, die Domains/URLs aus einer Konfigurationsdatei zu laden. Nur die kleinsten eingebetteten Plattformen sind für diesen Zweck möglicherweise nicht „praktisch“ 🙂

Versuchen Sie es mit dem ##-Operator

#define IV_SECURE secure.##IV_DOMAIN

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

    – e.James

    28. April 2009 um 14:38

  • Das Einfügen von Token (‘##’) oder das Stringisieren (‘#’) funktioniert ohne einige zusätzliche Dinge nicht.

    – Michael Burr

    28. April 2009 um 15:01 Uhr

Benutzer-Avatar von Peter Mortensen
Peter Mortensen

Was Sie benötigen, sind die Operatoren # und ## sowie eine automatische Zeichenfolgenverkettung.

Der Vorverarbeitungsoperator # 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

was sich in IV_SECURE ändern sollte

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

Dies wird automatisch zu „secure.domain.org“ verkettet (vorausgesetzt, die Phasen der Übersetzung sind in C und C++ dieselben).

Bitte, bitte lesen Sie die Kommentare, die zeigen, wie ich es geschafft habe, verwirrt zu sein. Bedenken Sie, dass ich in C durchaus erfahren bin, wenn auch vielleicht etwas 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 glaube, das OP hat nach der Zeichenfolgenverkettung (#) und nicht nach dem Einfügen von Token (##) gefragt. Ich habe jedoch nicht abgelehnt. Die Frage ist etwas zweideutig.

    – e.James

    28. April 2009 um 14:38

  • Das Einfügen von Token (‘##’) oder das Stringisieren (‘#’) funktioniert ohne einige zusätzliche Dinge nicht.

    – Michael Burr

    28. April 2009 um 15:01 Uhr

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

__TESTING

sind in C (ich kenne Objective C nicht) 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 strikte Obermenge von C sein, daher sollte dies ein gültiger Hinweis sein.

    – Chris Lutz

    28. April 2009 um 14:48

1454190cookie-checkMakros zum Erstellen von Strings in C

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

Privacy policy