Was ist die richtige Art und Weise der Umsetzung eine gute "itoa ()" - Funktion?
Ich Frage mich, ob meine Umsetzung eines "itoa" - Funktion korrekt ist. Vielleicht können Sie mir helfen es ein bisschen mehr "richtige" ist, ich bin mir ziemlich sicher, ich bin etwas fehlt. (Vielleicht gibt es bereits eine Bibliothek diese Weise die Umwandlung der Art, wie ich will, es zu tun, aber... konnte nicht finden)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char * itoa(int i) {
char * res = malloc(8*sizeof(int));
sprintf(res, "%d", i);
return res;
}
int main(int argc, char *argv[]) {
...
- Seien Sie vorsichtig. Es gibt nichts, um anzuzeigen, dass der Benutzer benötigt, um zu löschen Sie die return-pointer hinterher.
- Verwandte: stackoverflow.com/q/4351371/103167
- Sie hat nicht realisiert
itoa
. Sie nur weitergeleitet Ihren job, um die library-Funktionsprintf
die nicht den job für Sie.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die einzige wirkliche Fehler ist, dass Sie nicht überprüfen Sie den Rückgabewert von
malloc
für null.Den Namen
itoa
ist Art von bereits für eine andere Funktion, nicht-standard, aber nicht selten. Es muss nicht Speicher, sondern schreibt es in einen Puffer, sofern der Anrufer:Wenn Sie nicht wollen, verlassen Sie sich auf Ihrer Plattform mit, dass, würde ich immer noch raten, nach dem Muster. String-handling-Funktionen die neu zugewiesenen Speicher in C sind in der Regel mehr ärger als Sie Wert sind, auf lange Sicht, weil die meisten der Zeit, die Sie am Ende tut die weitere manipulation, und so haben Sie, um eine Menge von Zwischenergebnissen. Vergleichen Sie zum Beispiel:
vs.
Wenn Sie hatte Grund, besonders besorgt über die Leistung (zum Beispiel, wenn Sie implementieren eine stdlib-Stil-Bibliothek einschließlich
itoa
), oder wenn Sie waren die Umsetzung der Grundlagen, dasssprintf
nicht unterstützt, dann könnten Sie nicht aufrufensprintf
. Aber wenn Sie möchten, eine base-10-string, dann ist dein Erster Instinkt war richtig. Es gibt absolut nichts "Falsches" über die%d
Formatbezeichner.Hier ist eine mögliche Umsetzung
itoa
für Basis 10 nur:Hier ist eine, die enthält die snprintf-Stil Ansatz für Puffer-Längen:
snprintf(endptr, bytes, "%d", number)
- Dies würde verhindern, dass eine temporäre variable Erklärung und nicht diejenigen, die buffer-overflow-Möglichkeiten in diesem Beispiel-code.snprintf
direkt das ist der gleiche Grund, jemals jemand schreibt eine Funktion: zu Abstrakt, der Betrieb, die speziell für die Umwandlung eines integer zu einem string, im Gegensatz zu irgendeiner der vielen Dinge, diesnprintf
können mit den unterschiedlichen string-Formate. Es ist nur ein Puffer-überlauf, der Möglichkeit, in diesem code auf Plattformen, woint
mindestens 48 bits, und ich denke, dass Problem wurde gut abgedeckt anderswo. Fühlen Sie sich frei, zu verschmelzen, eins von denen in dieser Antwort 🙂snprintf
zurück nicht negativ auf das abschneiden - das ist ein pre-C99-ism in z.B. Microsoft_snprintf
und sehr alte glibc-Versionen. Es gibt die Anzahl der bytes, die geschrieben hatte, die Größe war ausreichend groß. Die überprüfung für die negative Rendite bedeutet, dass Sie verpassen abschneiden auf standard-Implementierungen.snprintf
ist gut für die "Messen, zuordnen, schreiben Sie" Muster, aber es hilft nicht viel mit kurz-Puffer IMO. Und das sogar noch, bevor Sie sich sorgen darüber, ob die Länge, die Sie haben übergeben, ist tatsächlich korrekt. Die sichere Handhabung von Strings in C ist hart.strcpy_strings_that_start_with_a
stattstrcpy
?atoi
, so dass es nicht viel im Vergleich mit der direkten Verwendung von snprintf, aber es tut mehr als nichts. Die Existenz vonatoi
machtitoa
eine besonders Natürliche Abstraktion.a
ich denke, vielleicht würde ich eine Funktion schreiben, dieasserts
das erste Zeichen und ruft dannstrcpy
. Auf ein release zu bauen, wäre es ein do-nothing-wrapper.v /= radix
schneller alsv = v /radix
ist nicht wahr. Jeder compiler erzeugt den gleichen code für beide Formen. Getestet habe ich es mit gcc-Optimierungen deaktiviert.*sp = '\0';
vorreturn len;
so dasssp
wird ein richtig null-terminierte ASCII-Zeichenkette, die Sie verwenden können, um Funktionen wiestrcpy
.Ich denke, Sie werden allozieren, vielleicht zu viel Speicher.
malloc(8*sizeof(int))
geben Sie 32 bytes auf den meisten Maschinen, das ist wahrscheinlich, übermäßige für eine text-Darstellung eines int.sizeof(int)*3+2
sollte immer ausreichend sein (jedes byte trägt 3 stellen oder weniger, und die zusätzlichen 2 sind für Zeichen und null-Terminierung.CHAR_BIT
größer als 9 ist. ZB. manche DSPs habenCHAR_BIT == 32
undsizeof(int) == 1
.((CHAR_BIT * sizeof(type) - 1) / 3 + 2)
für signed-Typen, oder((CHAR_BIT * sizeof(type)) / 3 + 1)
für unsigned-Typen.Einen guten
int
zu string oderitoa()
hat diese Eigenschaften;[INT_MIN...INT_MAX]
-, Basis -[2...36]
ohne Puffer-überlauf.int
Größe.unsigned
einen größeren positiven Bereich alsint
. In anderen Worten, nicht verwendenunsigned
.'-'
für negative zahlen, auch wennbase != 10
.Passen Sie die Fehlerbehandlung benötigt. (muss C99 oder später):
Ich bin mir nicht ganz sicher, wo Sie bekommen
8*sizeof(int)
als die maximal mögliche Anzahl der Zeichen --ceil(8 /(log(10) /log(2)))
ergibt sich ein Multiplikator von3*
. Darüber hinaus unter C99 und einige ältere POSIX-Plattformen können Sie erstellen, die eine passgenaue Zuweisung der version mitsprintf()
:HTH
%d
es ist nicht wirklich notwendig, da Sie arbeiten können, die max benötigt Raum zur compile-Zeit. Für einen 32bit int, es ist 12, also würde man normalerweise nicht zu viel sorgen über die Zuteilung. Dieses Allgemeine Muster der Aufrufsnprintf
zweimal ist absolut standard Zeug, aber.fand ich eine interessante Ressource im Umgang mit verschiedenen Themen, die mit der itoa Umsetzung
Sie würde vielleicht schauen Sie auch
itoa () - Implementierungen mit performance-tests
Sollten Sie eine Funktion in der
printf
Familie für diesen Zweck. Wenn Sie schreiben werden, das Ergebnis zustdout
oder eine Datei, verwenden Sieprintf
/fprintf
. Andernfalls verwenden Siesnprintf
mit einem Puffer groß genug, um3*sizeof(type)+2
bytes oder mehr.sprintf ist ziemlich langsam, wenn es um performance geht, ist es wahrscheinlich nicht die beste Lösung.
wenn die Basis-argument ist eine Potenz von 2 ist die Umwandlung kann getan werden, mit shift und Maskierung, und man kann vermeiden, die Umkehrung der Zeichenfolge, die durch die Aufnahme der Ziffern aus den höchsten Positionen. Zum Beispiel so etwas wie dieses für Basis=16
const char Ziffern[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
Für Dezimalzahlen gibt es auch eine nette Idee für die Verwendung einer statischen array groß genug, um dem Datensatz die zahlen in umgekehrter Reihenfolge, siehe hier
Sollte dies funktionieren:
Wenn Sie nicht wollen, verwenden Sie die math/floating-point-Funktionen (und noch die Verknüpfung in die Mathematik-Bibliotheken) Sie sollten in der Lage sein zu finden, nicht-floating-point-Versionen von log10 durch die Suche im Web und tun:
size_t len = my_log10( abs(x) ) + 1;
Geben könnten Sie 1 mehr byte als Sie benötigt, aber Sie hätten genug.
INT_MIN
.Gibt es ein paar Vorschläge, die ich machen könnte. Sie können einen statischen Puffer und strdup zu vermeiden, wiederholt die Zuweisung von zu viel Speicher auf nachfolgende Aufrufe. Ich würde auch hinzufügen, einige Fehler zu überprüfen.
Wenn diese aufgerufen wird, die in einer multithreaded-Umgebung, entfernen Sie "static" aus dem Puffer Erklärung.