itoa()
est une fonction très pratique pour convertir un nombre en chaîne. Linux ne semble pas avoir itoa()
, existe-t-il une fonction équivalente ou dois-je utiliser sprintf(str, "%d", num)
?
EDIT: Désolé, j'aurais dû me rappeler que cette machine est résolument non standard, après avoir branché diverses implémentations libc
non standard à des fins académiques ;-)
Comme itoa()
est en effet non standard, comme mentionné par plusieurs commentateurs utiles, il est préférable d’utiliser sprintf(target_string,"%d",source_int)
ou (mieux encore, car il est à l’abri des débordements de mémoire tampon) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int)
. Je sais que ce n'est pas aussi concis ni aussi cool que itoa()
, mais au moins, vous pouvez écrire une fois, exécuter tout le monde (tm) ;-)
Vous avez raison de dire que le gcc libc
par défaut n'inclut pas itoa()
, à l'instar de plusieurs autres plates-formes, car techniquement, il ne fait pas partie du standard. Voir ici pour un peu plus d’informations. Notez que vous devez
#include <stdlib.h>
Bien sûr, vous le savez déjà, car vous vouliez utiliser utiliseritoa()
sous Linux après l'avoir utilisé sur une autre plate-forme, mais ... le code (volé à partir du lien ci-dessus) ressemblerait à ceci:
Exemple
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Sortie:
Enter a number: 1750 decimal: 1750 hexadecimal: 6d6 binary: 11011010110
J'espère que cela t'aides!
Si vous l'appelez souvent, le conseil "n'utilisez que snprintf" peut être ennuyeux. Alors, voici ce que vous voulez probablement:
const char *my_itoa_buf(char *buf, size_t len, int num)
{
static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */
if (!buf)
{
buf = loc_buf;
len = sizeof(loc_buf);
}
if (snprintf(buf, len, "%d", num) == -1)
return ""; /* or whatever */
return buf;
}
const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }
itoa
n'est pas une fonction C standard. Vous pouvez implémenter le vôtre. Il est apparu dans la première édition de Kernighan et Ritchie'sLe langage de programmation C, à la page 60. La deuxième édition du langage de programmation C ("K & R2") contient les suite à l’implémentation de itoa
, à la page 64. Le livre note plusieurs problèmes liés à cette implémentation, notamment le fait que il ne gère pas correctement le nombre le plus négatif
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
La fonction reverse
utilisée ci-dessus est implémentée deux pages plus tôt:
#include <string.h>
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Edit: Je viens de découvrir std::to_string
dont le fonctionnement est identique à celui de ma fonction ci-dessous. Il a été introduit en C++ 11 et est disponible dans les versions récentes de gcc, au moins dès la version 4.5 si vous activez les extensions c ++ 0x .
itoa
manque dans gcc, mais ce n’est pas la fonction la plus pratique à utiliser car vous devez l’alimenter en mémoire tampon. J'avais besoin de quelque chose qui puisse être utilisé dans une expression alors je suis arrivé avec ceci:std::string itos(int n)
{
const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
char buffer[max_size] = {0};
sprintf(buffer, "%d", n);
return std::string(buffer);
}
Normalement, il serait plus prudent d’utiliser snprintf
au lieu de sprintf
, mais la taille du tampon est soigneusement dimensionnée pour ne pas être dépassée.
Voir un exemple: http://ideone.com/mKmZVE
Comme l'a écrit Matt J, il existe itoa
, mais ce n'est pas standard. Votre code sera plus portable si vous utilisez snprintf
.
La fonction suivante alloue juste assez de mémoire pour conserver la représentation sous forme de chaîne du nombre donné, puis écrit la représentation sous forme de chaîne dans cette zone à l'aide de la méthode standard sprintf
.
char *itoa(long n)
{
int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
if (n<0) len++; // room for negative sign '-'
char *buf = calloc(sizeof(char), len+1); // +1 for null
snprintf(buf, len+1, "%ld", n);
return buf;
}
N'oubliez pas de free
augmenter la mémoire allouée en cas de besoin:
char *num_str = itoa(123456789L);
// ...
free(num_str);
N.B. Comme snprintf copie n-1 octets, nous devons appeler snprintf (buf, len + 1, "% ld", n) (pas seulement snprintf (buf, len, "% ld", n))
Où se trouve la fonction itoa sous Linux?
Une telle fonction n'existe pas sous Linux. J'utilise ce code à la place.
/*
=============
itoa
Convert integer to string
PARAMS:
- value A 64-bit number to convert
- str Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
boolean sign = false;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = true;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
Voici une version nettement améliorée de la solution d'Archana. Cela fonctionne pour tous les radix 1-16, et les nombres <= 0, et cela ne devrait pas surcharger 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;
}
Lire le code des gars qui le font pour gagner leur vie vous procurera un long chemin.
Découvrez comment les gars de MySQL l'ont fait. La source est TRÈS BIEN COMMENCÉE et vous en apprendra beaucoup plus que des solutions bidouillées trouvées partout.
Implémentation de int2str par MySQL
Je fournis la mise en œuvre mentionnée ici; le lien est ici pour référence et doit être utilisé pour lire la mise en œuvre complète.
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *Dig_vec= upcase ? _Dig_vec_upper : _Dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = Dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = Dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
Si vous voulez juste les imprimer:
void binary(unsigned int n)
{
for(int shift=sizeof(int)*8-1;shift>=0;shift--)
{
if (n >> shift & 1)
printf("1");
else
printf("0");
}
printf("\n");
}
Où se trouve la fonction itoa sous Linux?
Comme itoa()
n'est pas standard en C, il existe différentes versions avec différentes signatures de fonctions.char *itoa(int value, char *str, int base);
est commun dans * nix.
Si Linux le manquait ou si le code ne veut pas limiter la portabilité, le code pourrait le rendre propre.
Ci-dessous, une version qui n’a pas de problème avec INT_MIN
et qui gère les tampons posant problème: 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);
}
Ci-dessous, une version C99 ou ultérieure qui gère n’importe quelle 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 C89 et ultérieur, 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);
copie directe dans le tampon: entier 64 bits
char* itoah(long num, char* s, int len)
{
long n, m = 16;
int i = 16+2;
int shift = 'a'- ('9'+1);
if(!s || len < 1)
return 0;
n = num < 0 ? -1 : 1;
n = n * num;
len = len > i ? i : len;
i = len < i ? len : i;
s[i-1] = 0;
i--;
if(!num)
{
if(len < 2)
return &s[i];
s[i-1]='0';
return &s[i-1];
}
while(i && n)
{
s[i-1] = n % m + '0';
if (s[i-1] > '9')
s[i-1] += shift ;
n = n/m;
i--;
}
if(num < 0)
{
if(i)
{
s[i-1] = '-';
i--;
}
}
return &s[i];
}
remarque: changez long à long long pour une machine 32 bits. long to int au cas où l'entier sur 32 bits. m est la base. Lorsque vous réduisez la base, augmentez le nombre de caractères (variable i). Lorsque vous augmentez la base, diminuez le nombre de caractères (mieux). En cas de type de données non signé, je deviens simplement 16 + 1.
j'ai essayé ma propre implémentation de itoa (), il semble que le travail en binaire, octal, décimal et hex
#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)
static char * my_itoa ( int value, char * str, int base )
{
int i,n =2,tmp;
char buf[BIN_LEN+1];
switch(base)
{
case 16:
for(i = 0;i<HEX_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%x" ,value);
break;
case 10:
for(i = 0;i<INT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%d" ,value);
break;
case 8:
for(i = 0;i<OCT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%o" ,value);
break;
case 2:
for(i = 0,tmp = value;i<BIN_LEN;++i)
{
if(tmp/base>0)
{
n++;
}
tmp/=base;
}
for(i = 1 ,tmp = value; i<n;++i)
{
if(tmp%2 != 0)
{
buf[n-i-1] ='1';
}
else
{
buf[n-i-1] ='0';
}
tmp/=base;
}
buf[n-1] = '\0';
strcpy(str,buf);
break;
default:
return NULL;
}
return str;
}
Le remplacement par snprintf n'est pas complet!
Il ne couvre que les bases: 2, 8, 10, 16, alors que itoa fonctionne pour les bases entre 2 et 36.
Depuis que je cherchais un remplaçant pour la base 32, je suppose que je devrai me coder!
Je préférerais ceci: https://github.com/wsq003/itoa_for_linux
Ce devrait être le plus rapide itoa () de tous les temps. Nous utilisons itoa () au lieu de sprintf () pour des raisons de performances. Un itoa () le plus rapide avec des fonctionnalités limitées est raisonnable et vaut la peine.
J'ai utilisé _itoa (...) sur RedHat 6 et le compilateur GCC. Ça marche.