2009-02-13 8 views
11
sscanf(input_str, "%5s", buf); //reads at max 5 characters from input_str to buf 

Aber ich brauche etwas wie% MACRO_SIZEs von% anstatt verwenden 5sWie Übergeben variabler Breite Spezifizierer in sscanf?

Eine triviale Lösung ist ein Format-String für die gleichen

char fmt_str[100] = "";  
snprintf(fmt_str, 100, "%%%ds", MACRO_SIZE); 
sscanf(input_str, fmt_str, buf); 

zu schaffen Gibt es einen besseren Weg, um das gleiche zu erreichen ?

Antwort

8

wenn Ihr MACRO_SIZE const bei der Kompilierung ist, können Sie dies versuchen:

#define MACRO_SIZE "5" 
snprintf(fmt_str, 100, "%" MACRO_SIZE "s", buf); 
+0

Die Einschränkung ist nicht so sehr, dass MACRO_SIZE als eine Konstante auswertet, aber dass seine Definition ein einfaches Literal ist, oder? Zum Beispiel ergibt eine Definition von (5 * 25 + 3) (die zur Kompilierzeit eine Konstante ergibt) 'snprintf (fmt_str, 100, "%" (5 * 25 + 3) "s", buf); – jhfrontz

9

Wie Stefan sagte, aber für sscanf() mehr richtig, die Frage zu beantworten, und mit ein bisschen mehr Makro Tricks:

#define MACRO_SIZE 5 

#define FORMAT(S) "%" #S "s" 
#define RESOLVE(S) FORMAT(S) 

char buf[MACRO_SIZE + 1]; 
sscanf(input_str, RESOLVE(MACRO_SIZE), buf); 

Dies verwendet Cs automatisches Zusammenfügen benachbarter Zeichenfolgenliterale, um die erforderliche Formatierungszeichenfolge zur Kompilierungszeit zu bilden. Dies funktioniert nur, wenn MACRO_SIZE ein Präprozessor-Makro ist, nicht, wenn es eine normale Laufzeitvariable ist.

Der zusätzliche Makroaufruf durch RESOLVE() benötigt wird, da sonst das Argument nicht zu seinem #define d Wert gelöst werden, und wir würden mit einer Formatierungszeichenfolge von "%MACRO_SIZEs" am Ende, das nicht das, was wir wollen, ist.

+0

Würdest du erwarten, dass dies funktioniert, wenn 'MACRO_SIZE' ein Ausdruck ist (zB' (4 + 1) 'oder verweist auf ein anderes Makro (zB' #define MACRO_SIZE (OTHER_MACRO - 1) ')? Wenn ich es versuchte, mit' gcc "E", um die Post-Präprozessor-Ausgabe anzuzeigen, es wurde nicht auf den endgültigen Wert erweitert. – meowsqueak

+0

@meowsqueak Nein, natürlich nicht, da es darauf angewiesen ist, dass benachbarte Zeichenfolgenliterale als einzelne Zeichenfolge betrachtet werden. 'MACRO_SIZE' muss eine Zahl sein. – unwind

1

Die "richtige" Lösung ist das, was Sie das Triviale nennen. All diese cleveren Makros (ich würde selbst m4 verwenden) werden Ihren Code weniger überschaubar machen, wenn Sie ihn einfach als Konstante belassen.

Das Problem, das Sie hier haben, ist Strings sind keine erstklassige Datenstruktur in C. Sie sind ein Array von Bytes. Dazu müssen Sie das Array erstellen, das die gewünschte Bedeutung haben soll, und Sie erstellen dieses Array mit sprintf. Es ist nicht schön, aber es ist korrekt.

Wenn Sie Leistungsprobleme haben, und Sie haben es bis hierher verfolgt, dann ja, beseitigen Sie die Funktionsaufrufe. Aber wenn der Wert für MACRO_SIZE nicht hundertmal wiederholt oder über mehrere Dateien verteilt wird, ändere ich einfach das Literal. Ein Makro täuscht nur mehr Flexibilität vor, sprintf bietet Ihnen Flexibilität.