Konvertieren Sie ein Präprozessor-Token in eine Zeichenfolge

Lesezeit: 3 Minuten

Benutzeravatar von davenpcj
davenpcj

Ich suche nach einer Möglichkeit, ein Präprozessor-Token in eine Zeichenfolge umzuwandeln.

Konkret habe ich irgendwo:

#define MAX_LEN 16

und ich möchte es verwenden, um einen Pufferüberlauf zu verhindern:

char val[MAX_LEN+1]; // room for \0
sscanf(buf, "%"MAX_LEN"s", val);

Ich bin offen für andere Möglichkeiten, dasselbe zu erreichen, aber nur die Standardbibliothek.

  • stackoverflow.com/questions/195975/…

    – Ciro Santilli OurBigBook.com

    5. Oktober 2015 um 13:43 Uhr

  • Mögliches Duplikat von C-Makros zum Erstellen von Zeichenfolgen

    – Richard Stelling

    6. Oktober 2015 um 10:33 Uhr

Dans Benutzeravatar
Dan

sehen http://www.decompile.com/cpp/faq/file_and_line_error_string.htm
speziell:

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)

Ihr Problem kann also gelöst werden, indem Sie es tun
sscanf(buf, "%" TOSTRING(MAX_LEN) "s", val);

  • Warum 2 Makros kaskadieren? Wäre ein TOSTRING nicht genug?

    – feedc0de

    5. Oktober 2017 um 12:52 Uhr

  • Siehe Antwort unten zur Double-Expansion-Stringifizierung. Der C/C++-Präprozessor ist schmutzig und hässlich und ich glaube, ohne einen Standard. Warum es also zwei statt einem braucht, kann ich nicht sagen, weil ich nicht recherchieren möchte.

    – Dan

    5. Oktober 2017 um 15:42 Uhr


  • @Daniel Brunner Ein einzelnes Makro fügt das Token selbst ein und ergibt buchstäblich "%" "MAX_LEN" "%" ein zweites Makro bewirkt das Token Wert geklebt werden, z. "16" weil die TOSTRING Makro macht den endgültigen Code äquivalent zu STRINGIFY(16).

    – Tim Sylvester

    2. Februar 2018 um 2:46 Uhr

  • @TimSylvester Ich wünschte, ich könnte dir diesen Kommentar wiederholen! 🙂

    – Matthias

    25. April 2019 um 15:54 Uhr


Ich habe im Internet eine Antwort gefunden.

#define VERSION_MAJOR 4
#define VERSION_MINOR 47

#define VERSION_STRING "v" #VERSION_MAJOR "." #VERSION_MINOR

Das obige funktioniert nicht, zeigt aber hoffentlich, was ich tun möchte, dh VERSION_STRING als “v4.47” enden zu lassen.

Um die richtige numerische Form zu erzeugen, verwenden Sie etwas wie

#define VERSION_MAJOR 4
#define VERSION_MINOR 47

#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_STRING "v" STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR)

#include <stdio.h>
int main() {
    printf ("%s\n", VERSION_STRING);
    return 0;
}

Es ist eine Weile her, aber das sollte funktionieren:

 sscanf(buf, "%" #MAX_LEN "s", val);

Wenn nicht, muss der Trick mit der “doppelten Erweiterung” ausgeführt werden:

 #define STR1(x)  #x
 #define STR(x)  STR1(x)
 sscanf(buf, "%" STR(MAX_LEN) "s", val);

  • Das erste wird nicht funktionieren; # stringisiert Makroargumente in Makroerweiterungen. Das zweite wird funktionieren.

    – Jonathan Leffler

    27. Oktober 2008 um 15:55 Uhr

  • @RaviRaj – weil # stringiert nur Makroargumente und die erste Zeile befindet sich nicht im Hauptteil eines Makros.

    – Jonathan Leffler

    30. August 2020 um 11:50 Uhr

Benutzeravatar von ephemient
vergänglich

Sie sollten den Double-Expansion-Stringification-Makro-Trick verwenden. Oder haben Sie einfach eine

#define MAX_LEN    16
#define MAX_LEN_S "16"

char val[MAX_LEN+1];
sscanf(buf, "%"MAX_LEN_S"s", val);

und halten Sie es synchron. (Das ist ein bisschen lästig, aber solange die Definitionen direkt nebeneinander stehen, werden Sie sich wahrscheinlich daran erinnern.)

In diesem speziellen Fall eigentlich nicht strncpy genügen?

strncpy(val, buf, MAX_LEN);
val[MAX_LEN] = '\0';

Wenn es wäre printfaber das wäre einfacher:

sprintf(buf, "%.*s", MAX_LEN, val);

Während einige der oben genannten “funktionieren”, würde ich persönlich empfehlen, nur eine einfache String-API anstelle des Drecks zu verwenden, der in libc enthalten ist. Es gibt eine Reihe portabler APIs, von denen einige auch für die einfache Integration in Ihr Projekt optimiert sind … und andere ustr haben einen geringen Platzbedarf und Unterstützung für Stack-Variablen.

Meine zwei Cent. In meinem Beispiel ist das zu generierende Format %16s%16s%d

#include <iostream>

#define MAX_LEN 16

#define AUX(x) #x
#define STRINGIFY(x) AUX(x)

int main() {
    char buffer[] = "Hello World 25";
    char val[MAX_LEN+1]; 
    char val2[MAX_LEN+1];
    int val3;

    char format[] = "%" STRINGIFY(MAX_LEN) "s" "%" STRINGIFY(MAX_LEN) "s" "%d";
    int result = sscanf(buffer, format, val, val2, &val3);
    std::cout<< val << std::endl;
    std::cout<< val2 << std::endl;
    std::cout<< val3 << std::endl;
    std::cout<<"Filled: " << result << " variables" << std::endl;
    std::cout << "Format: " << format << std::endl;
}

Ausgabe
Ausgang

1417920cookie-checkKonvertieren Sie ein Präprozessor-Token in eine Zeichenfolge

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

Privacy policy