Was ist die Verwendung des Formatbezeichners %n
in C? Kann jemand mit einem Beispiel erklären?Was ist der% n Formatbezeichner in C?
Antwort
Nichts gedruckt. Das Argument muss ein Zeiger auf einen vorzeichenbehafteten int sein, in dem die Anzahl der bisher geschriebenen Zeichen gespeichert ist.
#include <stdio.h>
int main()
{
int val;
printf("blah %n blah\n", &val);
printf("val = %d\n", val);
return 0;
}
vorheriger Code druckt:
blah blah
val = 5
Gibt +1, wenn Sie Beispielcode hinzufügen. –
Sie erwähnen, dass das Argument ein Zeiger auf ein vorzeichenbehaftetes int sein muss, dann haben Sie in Ihrem Beispiel ein unsigned int verwendet (wahrscheinlich nur ein Tippfehler). – bta
Können Sie erklären, warum es ein Zeiger sein muss? –
das Argument mit dem% n verbunden ist, wird in der printf an diesem Punkt gedruckt als int * und gefüllt mit der Anzahl der Gesamt Zeichen behandelt werden.
Von here sehen wir, dass es die Anzahl der bisher gedruckten Zeichen speichert.
n
Das Argument wird ein Zeiger auf eine Ganzzahl sein, in dem die Anzahl der Bytes, die durch diesen Aufruf zu einer derfprintf()
Funktionen so weit an den Ausgang geschrieben wird, geschrieben. Kein Argument wird konvertiert.
wäre ein Beispiel für die Verwendung sein:
int n_chars = 0;
printf("Hello, World%n", &n_chars);
n_chars
würde dann einen Wert von 12
haben.
Es wird nichts gedruckt. Es wird, um herauszufinden, verwendet, wie viele Zeichen gedruckt wurde, bevor %n
im Format-String erschienen und Ausgabe, die an die angegebene int:
#include <stdio.h>
int main(int argc, char* argv[])
{
int resultOfNSpecifier = 0;
_set_printf_count_output(1); /* Required in visual studio */
printf("Some format string%n\n", &resultOfNSpecifier);
printf("Count of chars before the %%n: %d\n", resultOfNSpecifier);
return 0;
}
Ich habe nicht wirklich viele gesehen praktische reale Welt verwendet die %n
Spezifizierer, aber ich erinnere mich, dass es in oldschool printf Verwundbarkeiten mit einer format string attack eine ganze Weile zurück verwendet wurde.
Etwas, das wie diese ging
void authorizeUser(char * username, char * password){
...code here setting authorized to false...
printf(username);
if (authorized) {
giveControl(username);
}
}
wo ein böswilliger Benutzer die Vorteile der Benutzerparameter nehmen könnte immer in printf als Format-String übergeben und eine Kombination aus %d
verwenden, %c
oder w/e, um durch der Aufruf-Stack und dann ändern Sie die Variable zu einem wahren Wert autorisiert.
Ja, es ist eine esoterische Verwendung, aber immer nützlich, wenn man einen Daemon schreibt, um Sicherheitslücken zu vermeiden? : D
Die meisten dieser Antworten erklären, was %n
tut (die nichts zu drucken ist und die Anzahl der Zeichen so weit zu einer int
Variable gedruckt zu schreiben), aber bisher hat niemand wirklich ein Beispiel dessen, was gegeben verwenden Sie es hat.Hier ist eine:
int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");
druckt:
hello: Foo
Bar
mit Foo und Bar ausgerichtet sind. (Es ist trivial, das zu tun, ohne %n
für dieses Beispiel verwendet wird, und in der Regel konnte man immer bricht den ersten printf
Aufruf:
int n = printf("%s: ", "hello");
printf("Foo\n");
printf("%*sBar\n", n, "");
Ob die etwas mehr Komfort ist etwas wert esoterisch wie %n
mit (und möglicherweise der Einführung Fehler) ist offen für Diskussionen.)
Oh my - das ist eine zeichenbasierte Version der Berechnung der Pixelgröße von String in einer bestimmten Schriftart! – Arkadiy
Können Sie erklären, warum & n und * s benötigt werden? Sind sie beide Zeiger? –
@AndrewS '& n' ist ein Zeiger (' & 'ist der Address-of-Operator); Ein Zeiger ist notwendig, da C ein Vorübergehender Wert ist, und ohne einen Zeiger konnte "printf" den Wert von "n" nicht ändern. Die Verwendung von '% s' in der 'printf'-Formatzeichenfolge gibt einen '% s'-Spezifizierer (in diesem Fall die leere Zeichenkette' '' ') unter Verwendung einer * Feldbreite * von' n'-Zeichen aus. Eine Erklärung der grundlegenden 'printf'-Prinzipien liegt grundsätzlich außerhalb des Umfangs dieser Frage (und der Antwort); Ich würde empfehlen, die 'printf'-Dokumentation zu lesen oder eine eigene Frage zu SO zu stellen. – jamesdlin
Bis jetzt sind alle Antworten darüber, dass %n
tut, aber nicht, warum jemand es in erster Linie wollen würde. Ich finde es mit sprintf
/snprintf
etwas nützlich, wenn Sie später möglicherweise die resultierende Zeichenfolge aufteilen oder ändern müssen, da der gespeicherte Wert ein Array-Index in der resultierenden Zeichenfolge ist. Diese Anwendung ist jedoch mit sscanf
viel nützlicher, insbesondere, da Funktionen in der scanf
-Familie die Anzahl der verarbeiteten Zeichen nicht zurückgeben, sondern die Anzahl der Felder.
Eine andere wirklich lahme Verwendung ist ein Pseudo-log10 zur gleichen Zeit frei zu bekommen, während eine Nummer als Teil einer anderen Operation gedruckt wird.
+1 für die Verwendung von '% n', obwohl ich über" alle Antworten ... "differieren möchte. = P – jamesdlin
Die bösen Jungs danken Ihnen für Ihre Verwendung von printf /% n, sprintf und sscanf;) – jww
@noloader: Wie so? * Die Verwendung von * '% n' hat absolut keine Verletzungsgefahr für einen Angreifer.Die unangebrachte Infamie von '% n' gehört wirklich zur dummen Praxis, eine Nachrichtenkette anstelle einer Formatzeichenkette als Formatargument zu übergeben. Diese Situation tritt natürlich niemals auf, wenn "% n" tatsächlich Teil einer intentionalen Formatzeichenfolge ist, die verwendet wird. –
% n ist C99, funktioniert nicht mit VC++.
'% n' existierte in C89. Es funktioniert nicht mit MSVC, weil Microsoft es aus Sicherheitsgründen standardmäßig deaktiviert hat; Sie müssen zuerst _set_printf_count_output aufrufen, um es zu aktivieren. (Siehe Merlyn Morgan-Grahams Antwort.) – jamesdlin
Nein, C89 definiert diese Funktion nicht/Backdoorbug. Siehe http://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628 ?? wo ist der URL-Tagger für Kommentare? – user411313
Sie sind einfach falsch. Sie ist in Tabelle B-1 ("printf" -Umsetzungen) des Anhangs B von K & R, 2. Auflage, deutlich aufgeführt. (Seite 244 meiner Kopie.) Oder siehe Abschnitt 7.9.6.1 (Seite 134) der ISO C90-Spezifikation. – jamesdlin
Es speichert den Wert der Anzahl der bisher gedruckten Zeichen in dieser printf()
Funktion.
Beispiel:
int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);
Die Ausgabe dieses Programms wird
Hello World
Characters printed so far = 12
wenn ich versuche, Sie Code gibt es mir: Hello World Characters so weit gedruckt = 36 ,,, ,, warum 36?! Ich benutze einen 32bit GCC in einer Windows-Maschine. –
Der andere Tag fand ich mich in einer Situation, wo %n
schön mein Problem lösen würde. Im Gegensatz zu my earlier answer kann ich in diesem Fall keine gute Alternative finden.
Ich habe ein GUI-Steuerelement, das einen bestimmten Text anzeigt. Dieses Steuerelement kann einen Teil dieses Textes fett (oder kursiv oder unterstrichen usw.) anzeigen, und ich kann angeben, welcher Teil durch Angabe der Indexindizes für Anfang und Ende festgelegt wird.
In meinem Fall, Ich erzeuge den Text an die Steuerung mit snprintf
, und ich würde eine der Substitutionen gerne fett gemacht werden. den Ausgangs Auffinden und Indizes auf diese Substitution endend ist nicht trivial, weil:
Der String mehr Substitutionen enthält, und eine der Substitutionen ist beliebig, vom Benutzer festgelegten Text. Dies bedeutet, dass eine textuelle Suche nach der Ersetzung, die mir wichtig ist, möglicherweise mehrdeutig ist.
Die Formatzeichenfolge ist möglicherweise lokalisiert und verwendet möglicherweise die POSIX-Erweiterung
$
für Positionsformatbezeichner. Daher ist das Suchen der ursprünglichen Formatzeichenfolge für die Formatspezifizierer selbst nicht trivial.Der Lokalisierungsaspekt bedeutet auch, dass ich die Formatzeichenfolge nicht einfach in mehrere Aufrufe an
snprintf
aufteilen kann.
Deshalb ist die einfachste Art und Weise die Indizes um eine bestimmte Substitution zu finden zu tun wäre:
char buf[256];
int start;
int end;
snprintf(buf, sizeof buf,
"blah blah %s %f yada yada %n%s%n yakety yak",
someUserSpecifiedString,
someFloat,
&start, boldString, &end);
control->set_text(buf);
control->set_bold(start, end);
Ich gebe dir +1 für den Anwendungsfall. Aber Sie werden ein Audit nicht bestehen, also sollten Sie wahrscheinlich einen anderen Weg finden, um den Anfang und das Ende des fett gedruckten Textes zu markieren. Es scheint, als ob drei 'snprintf' beim Überprüfen von Rückgabewerten gut funktionieren, da' snprintf' die Anzahl der geschriebenen Zeichen zurückgibt. Vielleicht etwas wie: 'int begin = snprintf (...," bla bla% s% f yada yada ", ...);' und 'int end = snprintf (...,"% s ", ...); 'und dann der Schwanz:' snprintf (..., "blah blah"); '. – jww
@jww Das Problem mit mehreren 'snprintf'-Aufrufen besteht darin, dass die Ersetzungen möglicherweise in anderen Gebietsschemas neu angeordnet werden, sodass sie nicht so aufgelöst werden können. – jamesdlin
Was der feinen Kunst des Lesens das Handbuch geworden ist? – Jens
Ich denke, die wirkliche Frage ist, was ist der ** POINT ** einer solchen Option? Warum würde jemand den Wert der gedruckten Zahlen wissen wollen, schreiben Sie viel weniger diesen Wert direkt in den Speicher. Es war, als ob die Entwickler gelangweilt waren und beschlossen, einen Fehler in den Kernel einzuführen. –