Das Konvertieren von etwas in eine Zeichenfolge sollte entweder 1) die resultierende Zeichenfolge zuweisen oder 2) ein char *
Ziel und eine Größe übergeben. Beispielcode unten:
Beide arbeiten für alle int
einschließlich INT_MIN
. Sie bieten eine konsistente Ausgabe, snprintf()
die nicht vom aktuellen Gebietsschema abhängt.
Methode 1: Rückgabe NULL
bei Speichermangel.
#define INT_DECIMAL_STRING_SIZE(int_type) ((CHAR_BIT*sizeof(int_type)-1)*10/33+3)
char *int_to_string_alloc(int x) {
int i = x;
char buf[INT_DECIMAL_STRING_SIZE(int)];
char *p = &buf[sizeof buf - 1];
*p = '\0';
if (i >= 0) {
i = -i;
}
do {
p--;
*p = (char) ('0' - i % 10);
i /= 10;
} while (i);
if (x < 0) {
p--;
*p = '-';
}
size_t len = (size_t) (&buf[sizeof buf] - p);
char *s = malloc(len);
if (s) {
memcpy(s, p, len);
}
return s;
}
Methode 2: NULL
Wird zurückgegeben, wenn der Puffer zu klein war.
static char *int_to_string_helper(char *dest, size_t n, int x) {
if (n == 0) {
return NULL;
}
if (x <= -10) {
dest = int_to_string_helper(dest, n - 1, x / 10);
if (dest == NULL) return NULL;
}
*dest = (char) ('0' - x % 10);
return dest + 1;
}
char *int_to_string(char *dest, size_t n, int x) {
char *p = dest;
if (n == 0) {
return NULL;
}
n--;
if (x < 0) {
if (n == 0) return NULL;
n--;
*p++ = '-';
} else {
x = -x;
}
p = int_to_string_helper(p, n, x);
if (p == NULL) return NULL;
*p = 0;
return dest;
}
[Bearbeiten] als Anfrage von @Alter Mann
(CHAR_BIT*sizeof(int_type)-1)*10/33+3
ist mindestens die maximale Anzahl, die char
erforderlich ist, um den Ganzzahlentyp mit Vorzeichen als Zeichenfolge zu codieren, die aus einem optionalen negativen Vorzeichen, Ziffern und einem Nullzeichen besteht.
Die Anzahl der nicht vorzeichenbehafteten Bits in einer vorzeichenbehafteten Ganzzahl beträgt nicht mehr als CHAR_BIT*sizeof(int_type)-1
. Eine Basis-10-Darstellung einer n
-bit-Binärzahl nimmt n*log10(2) + 1
Ziffern auf. 10/33
ist etwas mehr als log10(2)
. +1 für das Vorzeichen char
und +1 für das Nullzeichen. Andere Fraktionen könnten wie 28/93 verwendet werden.
Methode 3: Wenn man am Rande leben möchte und der Pufferüberlauf kein Problem darstellt, folgt eine einfache C99-Lösung oder eine spätere Lösung, die alle Probleme löst int
.
#include <limits.h>
#include <stdio.h>
static char *itoa_simple_helper(char *dest, int i) {
if (i <= -10) {
dest = itoa_simple_helper(dest, i/10);
}
*dest++ = '0' - i%10;
return dest;
}
char *itoa_simple(char *dest, int i) {
char *s = dest;
if (i < 0) {
*s++ = '-';
} else {
i = -i;
}
*itoa_simple_helper(s, i) = '\0';
return dest;
}
int main() {
char s[100];
puts(itoa_simple(s, 0));
puts(itoa_simple(s, 1));
puts(itoa_simple(s, -1));
puts(itoa_simple(s, 12345));
puts(itoa_simple(s, INT_MAX-1));
puts(itoa_simple(s, INT_MAX));
puts(itoa_simple(s, INT_MIN+1));
puts(itoa_simple(s, INT_MIN));
}
Beispielausgabe
0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648
printf
oder einer seiner Cousins sollte den Trick machen