Where is the itoa function in Linux?

itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, "%d", num)?

342455 次浏览

编辑: 对不起,我应该记得,这台机器是决定性的非标准,插入了各种非标准的 libc实现的学术目的; -)

由于 itoa()确实是非标准的,正如一些有帮助的评论者所提到的,最好使用 sprintf(target_string,"%d",source_int)或(更好的是,因为它是安全的缓冲区溢出) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int)。我知道它不像 itoa()那样简洁或者酷,但是至少你可以写一次,到处跑(tm) ; -)

以下是经过编辑的旧答案

您正确地指出,与其他几个平台一样,缺省的 gcc libc不包括 itoa(),因为它在技术上不是标准的一部分。有关更多信息,请参见 给你。请注意,你必须

#include <stdlib.h>

当然,您已经知道这一点,因为您想要在 Linux 上使用 使用 itoa(),但是... ... 代码(从上面的链接中盗用)看起来像:

例子

/* 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;
}

产出:

Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110

希望这个能帮上忙!

正如 Matt J 所写的,有 itoa,但它不是标准的。如果使用 snprintf,代码将更具可移植性。

我在 RedHat6和 GCC 编译器上使用了 _ itoa (...)。

如果您经常调用它,那么“只需使用 snprintf”的建议可能会很烦人。所以你可能想要的是:

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); }

您可以使用这个程序代替 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);
}

下面的函数分配足够的内存来保持给定数字的字符串表示形式,然后使用标准的 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;
}

当不需要的时候,不要忘记向 free分配内存:

char *num_str = itoa(123456789L);
// ...
free(num_str);

注意: 当 snprintf 复制 n-1字节时,我们必须调用 snprintf (buf,len + 1,“% ld”,n)(不仅仅是 snprintf (buf,len,“% ld”,n))

编辑: 我刚刚发现关于 std::to_string的操作和下面我自己的函数是一样的。它是在 C + + 11中引入的,并且可以在最新版本的 gcc 中使用,如果启用 c + + 0x 扩展,最早可以在4.5中使用。


不仅在 gcc 中缺少 itoa,而且它也不是最方便使用的函数,因为您需要为它提供一个缓冲区。我需要一些可以用在表达中的东西,所以我想到了这个:

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);
}

通常使用 snprintf而不是 sprintf会更安全,但是缓冲区的大小是经过仔细调整的,以免溢出。

看一个例子: http://ideone.com/mKmZVE

直接拷贝到 buffer: 64位整数 itoa 十六进制:

    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];
}

注意: 对于32位机器可以改为长至长。在32位整数的情况下,long 到 int。M 是基数。当减少基数时,增加字符数(变量 i)。当增加基数时,减少字符数(更好)。在无符号数据类型的情况下,i 就变为16 + 1。

这里是 Archana 解决方案的一个改进版本。它适用于任何基数1-16和数字 < = 0的情况,并且不应该损坏内存。

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;
}

我尝试了我自己的 itoa ()实现,它似乎在二进制,八进制,十进制和十六进制的工作

#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;
}

如果你只是想打印它们:

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");
}

itoa 不是标准的 C 函数。您可以实现自己的。它出现在第一版的 KernighanRitchie 的 C 程序设计语言,在第60页。C 语言编程语言(“ K & R 2”)的第二版在第64页包含以下 itoa的实现。本书指出了这个实现的几个问题,包括 它不能正确处理最负数

 /* 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);
}

上面使用的函数 reverse是在两页之前实现的:

 #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;
}
}

在 Linux 中 itoa 的功能在哪里?

由于 itoa()不是 C 语言中的标准,因此存在各种具有不同函数签名的版本。
char *itoa(int value, char *str, int base);在 * nix 中很常见。

如果 Linux 中缺少它,或者如果代码不想限制可移植性,代码可以将其变成自己的。

下面是一个版本,没有与 INT_MIN的麻烦,并处理问题缓冲区: NULL或不足的缓冲区返回 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);
}

下面是一个 C99或更高版本,可以处理任何基础[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);
}

对于 C89和向前兼容的代码,将内部循环替换为

  div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);

阅读那些以此为生的家伙的代码会让你走得更远。

看看 MySQL 的人是怎么做到的。来源是非常好的评论,并会教你更多的解决方案比到处都可以找到。

Int2str 的 MySQL 实现

我在这里提供了上面提到的实现; 链接在这里供参考,应该用于阅读完整的实现。

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;
}

在 Linux 中 itoa 的功能在哪里?

在 Linux 中没有这样的函数,我用这段代码代替。

/*
=============
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;
}

Glibc 内部实现

Glibc 2.28有一个内部实现:

这是在几个地方内部使用,但我不能找到它是否可以暴露或如何。

如果您愿意提取它,那么至少应该是一个健壮的实现。

这个问题问的是如何卷你自己的: 如何在 C 语言中将 int 转换为 string?

使用 snprintf 的替换不完整!

它只覆盖碱基: 2,8,10,16,而 itoa 适用于介于2和36之间的碱基。

因为我正在寻找32进制的替代品,我想我得自己编码了!

我更喜欢这个: https://github.com/wsq003/itoa_for_linux

这应该是有史以来最快的一次。出于性能原因,我们使用 itoa ()而不是 sprintf () ,因此一个具有有限特性的最快的 itoa ()是合理且值得的。