Linux中的itoa函数在哪里?
Posted
技术标签:
【中文标题】Linux中的itoa函数在哪里?【英文标题】:Where is the itoa function in Linux? 【发布时间】:2010-09-16 10:56:16 【问题描述】:itoa()
是一个非常方便的函数,可以将数字转换为字符串。 Linux好像没有itoa()
,有没有等价的功能还是非得用sprintf(str, "%d", num)
?
【问题讨论】:
有什么理由不使用sprintf(str, "%d", num)
?是不是比itoa
慢很多?
@javapowered,一方面,itoa
允许任意基础转换,printf
说明符不允许。
@javapowered sprintf() 不是信号安全的
有什么理由不使用标准库中的gcvt()
?
【参考方案1】:
编辑:抱歉,我应该记得这台机器绝对是非标准的,为了学术目的插入了各种非标准的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()
是正确的,因为它在技术上不是标准的一部分。有关更多信息,请参阅here。请注意,您必须
#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
希望这会有所帮助!
【讨论】:
嗯,在 Debian 上编译它给了我“对 `itoa' 的未定义引用”。可能是我的系统出了点问题。 我在 Ubuntu 8.04 上得到了同样的结果。我在 stdio.h 或 stdlib.h 中也找不到对 itoa 的引用(并不令人惊讶,因为它不是标准的一部分) 已编辑以确保正确性,谢谢大家!抱歉,我总是忘记这不是一个普通的 Linux 机器 ;-) 我已经编辑了答案以包含缓冲区大小参数;我相信一切都是现在应该的样子,我认为论点本身的顺序没有问题。我错过了什么吗? 它不适用于 Linux?问题/答案的结果是什么(非标准似乎都是 linux?)【参考方案2】:itoa
不是标准的 C 函数。你可以实现你自己的。它出现在 Kernighan 和 Ritchie's The C Programming Language 的第一版中,第 60 页。The C Programming Language 的第二版(" K&R2") 包含 itoa
的以下实现,第 64 页。本书指出了此实现的几个问题,包括 它不能正确处理最大负数
/* 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;
【讨论】:
【参考方案3】:如果您经常调用它,“只使用 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);
【讨论】:
这不仅仅是非线程安全的,它根本不是很安全:- void some_func(char* a, char* b); some_func(itoa(123), itoa(456));想知道函数接收到什么吗? 另外,const
限定符对函数返回类型没有任何作用——如果你打开编译器警告你会知道这一点:)
@cat 但是这里没有任何 const 限定的返回类型。 const char *
是一个指向 const 的非 const 指针,这很有意义并且是正确的。
@Chortos-2 这很有趣,你当然是完全正确的——我没有意识到 const
在 const int f (void) ...
和 const int* f (void) ...
之间的语义差异,但是现在用编译器试过了,很有意义。
静态缓冲区的大小完全没有意义,因为放入其中的字符串不是二进制的。在典型的机器上它将是 32 个字符,但是(假设 32 位 int
)最长的字符串是 "-2147483648"
,它只需要 12 个字符。不过,也许这是一个安全、慷慨的上限?【参考方案4】:
编辑:我刚刚发现了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
【讨论】:
问题似乎是关于 C 的,它没有std::
等内容。【参考方案5】:
正如 Matt J 所写,有 itoa
,但这不是标准的。如果您使用snprintf
,您的代码将更加可移植。
【讨论】:
【参考方案6】:以下函数分配刚好足够的内存来保存给定数字的字符串表示,然后使用标准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))
【讨论】:
调用你的函数itoa
不是一个好主意,但要赋予它与itoa
的实际实现不同的行为。这个函数是一个不错的主意,但可以叫它别的名字:) 我还建议使用snprintf
来计算缓冲区长度而不是浮点字符串;浮点可能有极端情况的不准确性。还有don't cast calloc
感谢您的建议。
如果需要一个长整数,应该使用labs
。否则它可能会被截断。
snprintf
到一个固定大小的 tmp 缓冲区,如 char buf[64]
以获取长度,然后 malloc
并复制到该缓冲区。与malloc
相比,calloc
没有任何好处,因为您写入了所有字节。一个非常短的字符串的额外复制没有调用浮点 log10 那么糟糕。但是,如果您有一个位扫描函数可以可靠地内联到有效的东西(例如 x86 上的bsr
),则使用整数 log2 进行快速近似可能会很有用。 (替代方案:malloc
一个 64 字节的缓冲区,然后在您知道最终长度后 realloc
。)【参考方案7】:
阅读那些以此为生的人的代码会让你走得很远。
看看 mysql 的人是如何做到的。来源得到了很好的评价,它会教给你比到处都是破解的解决方案更多的东西。
MySQL's implementation of int2str
我在这里提供了提到的实现;该链接可供参考,应用于阅读完整的实现。
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;
【讨论】:
始终欢迎提供指向潜在解决方案的链接,但请add context around the link,以便您的其他用户知道它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。考虑到仅仅是指向外部站点的链接是Why and how are some answers deleted? 的一个可能原因。 那么您在此处发布的 sn-p 有什么好处呢?未来的读者应该注意什么?【参考方案8】: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;
【讨论】:
您应该编辑您的答案以解释此代码如何回答问题。 代码错误...负值不起作用 calandoa,你能给出不起作用的精确值(值,基数)吗? @rick-rick-rick(不要忘记@,以便通知用户!):正基数和负值。顺便说一句,不要使用负基数,或者正确使用:en.wikipedia.org/wiki/Negative_base【参考方案9】:我尝试了自己的 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;
【讨论】:
【参考方案10】:直接复制到缓冲区: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 位机器,将 long 更改为 long long。对于 32 位整数,long 为 int。 m 是基数。减少基数时,增加字符数(变量 i)。增加基数时,减少字符数(更好)。在无符号数据类型的情况下,i 变为 16 + 1。
【讨论】:
【参考方案11】:这是 Archana 解决方案的改进版本。它适用于任何基数 1-16 和数字
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;
【讨论】:
【参考方案12】:如果您只想打印它们:
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");
【讨论】:
【参考方案13】: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);
以下是处理任何基础 [2...36] 的 C99 或更高版本
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);
【讨论】:
【参考方案14】:glibc 内部实现
glibc 2.28 有一个内部实现:
stdio-common/_itoa.c sysdeps/generic/_itoa.h在内部好几个地方都用到了,但是我找不到它是否可以暴露或如何暴露。
如果你愿意提取它,至少这应该是一个健壮的实现。
这个问题问如何滚动你自己的:How to convert an int to string in C?
【讨论】:
【参考方案15】:我更喜欢这个:https://github.com/wsq003/itoa_for_linux
它应该是有史以来最快的 itoa()。出于性能原因,我们使用 itoa() 而不是 sprintf(),因此具有有限功能的最快 itoa() 是合理且值得的。
【讨论】:
【参考方案16】:snprintf 的替换还没有完成!
它仅涵盖碱基:2、8、10、16,而 itoa 适用于 2 到 36 之间的碱基。
由于我正在寻找 base 32 的替代品,我想我必须自己编写代码!
【讨论】:
【参考方案17】:我在 RedHat 6 和 GCC 编译器上使用了 _itoa(...)。它有效。
【讨论】:
【参考方案18】:你可以用这个程序代替 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);
【讨论】:
这段代码有很多错误:1) 实际上没有正确转换十六进制。 2) 根本不转换 0。 3) 不适用于负数。 4) 不检查缓冲区溢出。我将很快发布此代码的改进版本。以上是关于Linux中的itoa函数在哪里?的主要内容,如果未能解决你的问题,请参考以下文章