referencia - ¿Dónde está la función itoa en Linux?
referencia a `itoa'' sin definir (15)
itoa()
es una función realmente útil para convertir un número en una cadena. Linux no parece tener itoa()
, ¿hay una función equivalente o tengo que usar sprintf(str, "%d", num)
?
¿Dónde está la función itoa en Linux?
Como itoa()
no es estándar en C, existen varias versiones con varias firmas de funciones.
char *itoa(int value, char *str, int base);
es común en * nix.
Si falta en Linux o si el código no quiere limitar la portabilidad, el código podría hacerlo suyo.
Debajo hay una versión que no tiene problemas con INT_MIN
y maneja los buffers problemáticos: NULL
o un buffer insuficiente devuelve 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);
}
Debajo hay una versión C99 o posterior que maneja cualquier 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);
}
Para un código compatible con C89 y posterior, reemplace el lazo interno con
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
¿Dónde está la función itoa en Linux?
No hay tal función en Linux. Yo uso este código en su lugar.
/*
=============
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;
}
Aquí hay una versión mejorada de la solución de Archana. Funciona para cualquier base 1-16, y números <= 0, y no debería dañar la memoria.
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;
}
Como Matt J escribió, hay itoa
, pero no es estándar. Su código será más portátil si usa snprintf
.
EDIT: Perdón, debería haber recordado que esta máquina es decididamente no estándar, habiendo conectado varias implementaciones de libc
no estándar para fines académicos ;-)
Como itoa()
es estándar, como lo mencionaron varios comentaristas útiles, es mejor usar sprintf(target_string,"%d",source_int)
o (mejor aún, porque está a salvo de desbordamientos de búfer) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int)
. Sé que no es tan conciso ni genial como itoa()
, pero al menos puedes Escribir una vez, ejecutar en todas partes (tm) ;-)
Aquí está la respuesta antigua (editada)
Tiene razón al afirmar que la gcc libc
predeterminada no incluye itoa()
, como muchas otras plataformas, debido a que técnicamente no es parte del estándar. Mira here para un poco más de información. Tenga en cuenta que tiene que
#include <stdlib.h>
Por supuesto, ya sabes esto, porque querías usar itoa()
en Linux después de presumiblemente usarlo en otra plataforma, pero ... el código (robado del enlace de arriba) se vería así:
Ejemplo
/* 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;
}
Salida:
Enter a number: 1750 decimal: 1750 hexadecimal: 6d6 binary: 11011010110
¡Espero que esto ayude!
He usado _itoa (...) en el compilador RedHat 6 y GCC. Funciona.
La función siguiente asigna suficiente memoria para mantener la representación de cadena del número dado y luego escribe la representación de cadena en esta área utilizando el método sprintf
estándar.
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;
}
No olvide free
la memoria asignada cuando no la necesite:
char *num_str = itoa(123456789L);
// ...
free(num_str);
NB Como snprintf copia n-1 bytes, tenemos que llamar snprintf (buf, len + 1, "% ld", n) (no solo snprintf (buf, len, "% ld", n))
Leer el código de chicos que lo hacen para ganarse la vida te dará un LARGO CAMINO.
Mira cómo lo hicieron los chicos de MySQL. La fuente está MUY BIEN COMENTADA y le enseñará mucho más que soluciones pirateadas que se encuentran por todos lados.
Implementación de MySQL de int2str
Proporciono la implementación mencionada aquí; el enlace está aquí para referencia y debe usarse para leer la implementación completa.
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;
}
Probé mi propia implementación de itoa (), parece que funciona en binario, octal, decimal y hexagonal
#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;
}
Puede usar este programa en lugar de sprintf.
void itochar(int x, char *buffer, int radix);
int main()
{
char buffer[10];
itochar(725, buffer, 10);
printf ("/n %s /n", buffer);
return 0;
}
void itochar(int x, char *buffer, int radix)
{
int i = 0 , n,s;
n = s;
while (n > 0)
{
s = n%radix;
n = n/radix;
buffer[i++] = ''0'' + s;
}
buffer[i] = ''/0'';
strrev(buffer);
}
Si lo llama mucho, el consejo de "simplemente use snprintf" puede ser molesto. Entonces esto es lo que probablemente quieras:
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); }
Si solo quieres imprimirlos:
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");
}
copia directa al búfer: 64 bits entero itoa hex:
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];
}
nota: cambie de largo a largo para la máquina de 32 bits. largo a int en caso de un entero de 32 bits. m es la raíz. Cuando disminuya la base, aumente el número de caracteres (variable i). Al aumentar la base, disminuya el número de caracteres (mejor). En el caso de tipo de datos sin signo, me acabo de convertir en 16 + 1.
itoa
no es una función C estándar. Usted puede implementar el suyo propio. Apareció en la primera edición de The C Programming Language de Kernighan y Ritchie , en la página 60. La segunda edición de The C Programming Language ("K & R2") contiene la siguiente implementación de itoa
, en la página 64. El libro señala varios problemas con este implementación, incluido el hecho de que no maneja correctamente el número más negativo
/* 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 función reverse
utilizada anteriormente se implementa dos páginas antes:
#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;
}
}
Editar: Acabo de descubrir acerca de std::to_string
que es idéntico en funcionamiento a mi propia función a continuación. Se introdujo en C ++ 11 y está disponible en versiones recientes de gcc, al menos tan pronto como 4.5 si habilita las extensiones c ++ 0x.
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);
}
Por lo general, sería más seguro usar snprintf
lugar de sprintf
pero el buffer es cuidadosamente dimensionado para que sea inmune al desbordamiento.
Vea un ejemplo: http://ideone.com/mKmZVE