itoa()
est une fonction très pratique pour convertir un nombre en chaîne de caractères. Linux ne semble pas avoir itoa()
existe-t-il une fonction équivalente ou dois-je utiliser la fonction sprintf(str, "%d", num)
?
Réponses
Trop de publicités?Voici une version très améliorée de la solution d'Archana. Elle fonctionne pour n'importe quel radix de 1 à 16, et les nombres <= 0, et ne devrait pas accabler la mémoire.
static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";
static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
for (int index = 0; index < (len / 2); index++)
{
char ch = buffer[index];
buffer[index] = buffer[len - index - 1];
buffer[len - index - 1] = ch;
}
}
static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
if (radix == 10)
{
if (len < (bufferSize - 1))
{
buffer[len++] = '-';
buffer[len] = '\0';
}
}
else
{
int twosCompIndex = 0;
for (int index = 0; index < len; index++)
{
if ((buffer[index] >= '0') && (buffer[index] <= '9'))
{
twosCompIndex = buffer[index] - '0';
}
else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
{
twosCompIndex = buffer[index] - 'A' + 10;
}
else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
{
twosCompIndex = buffer[index] - 'a' + 10;
}
twosCompIndex += (16 - radix);
buffer[index] = _twosComp[twosCompIndex];
}
if (len < (bufferSize - 1))
{
buffer[len++] = _numberSystem[radix - 1];
buffer[len] = 0;
}
}
return len;
}
static int twosNegation(const int x, const int radix)
{
int n = x;
if (x < 0)
{
if (radix == 10)
{
n = -x;
}
else
{
n = ~x;
}
}
return n;
}
static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
int strlen = 0;
int n = twosNegation(x, radix);
int nuberSystemIndex = 0;
if (radix <= 16)
{
do
{
if (strlen < (bufferSize - 1))
{
nuberSystemIndex = (n % radix);
buffer[strlen++] = _numberSystem[nuberSystemIndex];
buffer[strlen] = '\0';
n = n / radix;
}
else
{
break;
}
} while (n != 0);
if (x < 0)
{
strlen = negateBuffer(buffer, bufferSize, strlen, radix);
}
safestrrev(buffer, bufferSize, strlen);
return buffer;
}
return NULL;
}
Où se trouve la fonction itoa dans Linux ?
Comme itoa()
n'est pas standard en C, il existe plusieurs versions avec différentes signatures de fonctions.char *itoa(int value, char *str, int base);
est commun dans *nix.
Si elle est absente de Linux ou si le code ne veut pas limiter la portabilité, le code pourrait la créer lui-même.
Vous trouverez ci-dessous une version qui n'a pas de problème de INT_MIN
et gère les tampons à problèmes : NULL
ou un tampon insuffisant renvoie NULL
.
#include <stdlib.h>
#include <limits.h>
#include <string.h>
// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object) ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)
char *itoa_x(int number, char *dest, size_t dest_size) {
if (dest == NULL) {
return NULL;
}
char buf[SIGNED_PRINT_SIZE(number)];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = (char) ('0' - neg_num % 10);
neg_num /= 10;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Voici une version C99 ou ultérieure qui gère toute base [2...36].
char *itoa_x(int number, char *dest, size_t dest_size, int base) {
if (dest == NULL || base < 2 || base > 36) {
return NULL;
}
char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to avoid UB of `abs(INT_MIN)`
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
neg_num /= base;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Pour un code conforme à la norme C89 et aux normes ultérieures, remplacez la boucle interne par
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
implémentation interne de la glibc
La glibc 2.28 possède une implémentation interne :
qui est utilisé à plusieurs endroits en interne, mais je n'ai pas pu trouver s'il peut être exposé ou comment.
Au moins, cela devrait être une implémentation robuste si vous êtes prêt à l'extraire.
Cette question porte sur la façon de rouler les vôtres : Comment convertir un int en string en C ?
Je préférerais ceci : https://github.com/wsq003/itoa_for_linux
Ce devrait être le itoa() le plus rapide de tous les temps. Nous utilisons itoa() au lieu de sprintf() pour des raisons de performance, donc un itoa() plus rapide avec des fonctionnalités limitées est raisonnable et utile.
4 votes
Toute raison de ne pas utiliser
sprintf(str, "%d", num)
? est-il beaucoup plus lent queitoa
?5 votes
@javapowered, pour commencer,
itoa
permet une conversion arbitraire des bases,printf
les spécificateurs ne le font pas.0 votes
@javapowered sprintf() n'est pas sûr du signal
0 votes
Toute raison de ne pas utiliser
gcvt()
à partir de la bibliothèque standard ?