My_itoa在C++中的我的itoa(数值转标准字符串)函数
2013-10-21 16:16
267 查看
itoa with GCC
IntroductionCredits
Development
Latest Versions
Performance Comparison
How do I use itoa() with GCC?
Arrgghh C/C++! It would appear thatitoa()isn't ANSI C standard and doesn't work with GCC on Linux (at least the version I'm using). Things like this are frustrating especially if you want your code to work on different platforms (Windows/Linux/Solaris/whatever).
Many people say that you should just use sprintf to write to a character string but that doesn't allow for one of the features of itoa(); the ability to write in a base other than 10. This page contains a series of evolving versions of an itoa implementation.
The oldest are near the top and the
latest at the bottom. Please make sure that you use the
latest version.
Credits
Before we go any further, I would like to say thanks to the people that contributed to the solutions below. This function has been put together by contributions from Stuart Lowe (that's me), Robert Jan Schaper, Ray-Yuan Sheu, Rodrigo de Salvo Braz, Wes Garland,John Maloney, Brian Hunt, Fernando Corradi and Lukás Chmela.
Development
Below is an early versiondescribed by Robert Jan Schaper on Google groups:
char* version 0.1
[code] char* itoa(int val, int base){ static char buf[32] = {0}; int i = 30; for(; val && i ; --i, val /= base) buf[i] = "0123456789abcdef"[val % base]; return &buf[i+1]; }
[/code]
This doesn't quite look like the implementation I am used to which is more like
itoa(int value, char* buffer, int radix). In the end I have made my own version which uses a std::string instead of a character string.
std::string version 0.1
[code] void my_itoa(int value, std::string& buf, int base){ int i = 30; buf = ""; for(; value && i ; --i, value /= base) buf = "0123456789abcdef"[value % base] + buf; }
[/code]
Update: (2005/02/11)
Ray-Yuan Sheu sent me an email with an improved version which does a bit more error checking for things like a base that is out of range and for negative integers.
Update: (2005/04/08)
Rodrigo de Salvo Braz spotted a bug that meant nothing was returned when the input was zero. It now returns "0". This bug has also been spotted by Luc Gallant.
std::string version 0.2
[code] /** * C++ version std::string style "itoa": */ std::string itoa(int value, unsigned int base) { const char digitMap[] = "0123456789abcdef"; std::string buf; // Guard: if (base == 0 || base > 16) { // Error: may add more trace/log output here return buf; } // Take care of negative int: std::string sign; int _value = value; // Check for case when input is zero: if (_value == 0) return "0"; if (value < 0) { _value = -value; sign = "-"; } // Translating number to string with base: for (int i = 30; _value && i ; --i) { buf = digitMap[ _value % base ] + buf; _value /= base; } return sign.append(buf); }
[/code]
Update: (2005/05/07)
Wes Garland says that
lltostrexists under Solaris and several other unices. It should return a
char *of a long long in multiple number bases. There is also
ulltostrfor unsigned values.
Update: (2005/05/30)
John Maloney has pointed out various problems with the previous implementation. One of the major issues was the amount of heap allocation going on. He suggested that a lot of this be removed to speed up the algorithm. Below are two versions based on his excellent
suggestions. The
char*version is at least 10 times faster than the code above. The new
std::stringversion is 3 times faster than before. Although the
char*version is faster, you should check that you have allocated enough space to hold the output.
std::string version 0.3
[code] /** * C++ version std::string style "itoa": */ std::string itoa(int value, int base) { enum { kMaxDigits = 35 }; std::string buf; buf.reserve( kMaxDigits ); // Pre-allocate enough space. // check that the base if valid if (base < 2 || base > 16) return buf; int quotient = value; // Translating number to string with base: do { buf += "0123456789abcdef"[ std::abs( quotient % base ) ]; quotient /= base; } while ( quotient ); // Append the negative sign for base 10 if ( value < 0 && base == 10) buf += '-'; std::reverse( buf.begin(), buf.end() ); return buf; }
[/code]
char* version 0.2
[code]
/**
* C++ version char* style "itoa":
*/
char* itoa( int value, char* result, int base ) {
// check that the base if valid
if (base < 2 || base > 16) { *result = 0; return result; }
char* out = result;
int quotient = value;
do {
*out = "0123456789abcdef"[ std::abs( quotient % base ) ];
++out;
quotient /= base;
} while ( quotient );
// Only apply negative sign for base 10
if ( value < 0 && base == 10) *out++ = '-';
std::reverse( result, out );
*out = 0;
return result;
}
[/code]
Update: (2006/10/15)
Luiz Gon?lves tells me that although not an ANSI standard, itoa comes in many packages and it is written in many textbooks. He suggests a version written in pure ANSI C based on a version from Kernighan & Ritchie's
Ansi C. A base error is reported by the return of an empty string but the function does no checks of sizes and no allocations. This version is provided below along with a slightly modified version (architecture specific tweaks), the
std::stringversion and the C++
char* itoa()version.
[code]
/**
* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C":
*/
void strreverse(char* begin, char* end) {
char aux;
while(end>begin)
aux=*end, *end--=*begin, *begin++=aux;
}
void itoa(int value, char* str, int base) {
static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
char* wstr=str;
int sign;
// Validate base
if (base<2 || base>35){ *wstr='\0'; return; }
// Take care of sign
if ((sign=value) < 0) value = -value;
// Conversion. Number is reversed.
do *wstr++ = num[value%base]; while(value/=base);
if(sign<0) *wstr++='-';
*wstr='\0';
// Reverse string
strreverse(str,wstr-1);
}
[code]
/**
* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C"
* with slight modification to optimize for specific architecture:
*/
void strreverse(char* begin, char* end) {
char aux;
while(end>begin)
aux=*end, *end--=*begin, *begin++=aux;
}
void itoa(int value, char* str, int base) {
static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
char* wstr=str;
int sign;
div_t res;
// Validate base
if (base<2 || base>35){ *wstr='\0'; return; }
// Take care of sign
if ((sign=value) < 0) value = -value;
// Conversion. Number is reversed.
do {
res = div(value,base);
*wstr++ = num[res.rem];
}while(value=res.quot);
if(sign<0) *wstr++='-';
*wstr='\0';
// Reverse string
strreverse(str,wstr-1);
}
Update: (2009/07/08)
Over the past year I've had a few suggestions for improvements to both the std::string and char* versions of the code. I've finally had time to test them.
In the std::string version, Brian Hunt suggested to move the reserve after the base check to save memory allocations. This does speed things up a little.
std::string version 0.4
[code] /** * C++ version 0.4 std::string style "itoa": */ std::string itoa(int value, int base) { std::string buf; // check that the base if valid if (base < 2 || base > 16) return buf; enum { kMaxDigits = 35 }; buf.reserve( kMaxDigits ); // Pre-allocate enough space. int quotient = value; // Translating number to string with base: do { buf += "0123456789abcdef"[ std::abs( quotient % base ) ]; quotient /= base; } while ( quotient ); // Append the negative sign if ( value < 0) buf += '-'; std::reverse( buf.begin(), buf.end() ); return buf; }
[/code]
There have also been several suggestions for improvements to the char* version of the code. Fernando Corradi suggested moving the abs() so that it is used only once and not using the modulus operator (%) but rather calculating it by hand saving a division.
This does speed things up a little:
char* version 0.3
[code]
/**
* C++ version 0.3 char* style "itoa":
*/char* itoa( int value, char* result, int base ) {
// check that the base if valid
if (base < 2 || base > 16) { *result = 0; return result; }
char* out = result;
int quotient = abs(value);
do {
const int tmp = quotient / base;
*out = "0123456789abcdef"[ quotient - (tmp*base) ];
++out;
quotient = tmp;
} while ( quotient );
// Apply negative sign
if ( value < 0) *out++ = '-';
std::reverse( result, out );
*out = 0;
return result;
}
[/code]
However, Lukás Chmela has re-written the code so that it doesn't have a "most negative number" bug:
char* version 0.4
[code]
/**
* C++ version 0.4 char* style "itoa":
* Written by Lukás Chmela
* Released under GPLv3.
*/char* itoa(int value, char* result, int base) {
// check that the base if valid
if (base < 2 || base > 36) { *result = '\0'; return result; }
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
} while ( value );
// Apply negative sign
if (tmp_value < 0) *ptr++ = '-';
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return result;
}
[/code]
Latest Versions
Below are the latest versions of the itoa function using eitherchar*or
std::stringas you prefer. I haven't included the Kernighan & Ritchie based versions in this section because I'm not sure what the copyright status is for those. However, the functions below have been developed by the people mentioned on this page
and are available for use.
std::string version 0.4
[code] /** * C++ version 0.4 std::string style "itoa": * Contributions from Stuart Lowe, Ray-Yuan Sheu, * Rodrigo de Salvo Braz, Luc Gallant, John Maloney * and Brian Hunt */ std::string itoa(int value, int base) { std::string buf; // check that the base if valid if (base < 2 || base > 16) return buf; enum { kMaxDigits = 35 }; buf.reserve( kMaxDigits ); // Pre-allocate enough space. int quotient = value; // Translating number to string with base: do { buf += "0123456789abcdef"[ std::abs( quotient % base ) ]; quotient /= base; } while ( quotient ); // Append the negative sign if ( value < 0) buf += '-'; std::reverse( buf.begin(), buf.end() ); return buf; }
[/code]
char* version 0.4
[code]
/**
* C++ version 0.4 char* style "itoa":
* Written by Lukás Chmela
* Released under GPLv3.
*/char* itoa(int value, char* result, int base) {
// check that the base if valid
if (base < 2 || base > 36) { *result = '\0'; return result; }
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
} while ( value );
// Apply negative sign
if (tmp_value < 0) *ptr++ = '-';
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return result;
}
[/code]
Performance Comparsion
I've done some testing of the versions of itoa by finding the average time required to perform conversions, of the integers in the range -32768 to 32767, in every base from base 2 to base 20 (the code only works up to base 16 so the extra bases are justthere as tests). The summary is presented in the following table:
function | relative time |
---|---|
char* style "itoa" (v 0.2)char* itoa(int value, char* result, int base) | 1.0 (XP, Cygwin, g++) |
char* style "itoa" (v 0.3)char* itoa(int value, char* result, int base) | 0.93 |
char* style "itoa" (v 0.4)char* itoa(int value, char* result, int base) | 0.72 |
Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" with modification to optimize for specific architecturevoid itoa(int value, char* str, int base) | 0.92 |
std::string style "itoa" (v 0.3)std::string itoa(int value, int base) | 41.5 |
std::string style "itoa" (v 0.4)std::string itoa(int value, int base) | 40.8 |
http://blog.csdn.net/aw344/
相关文章推荐
- C++输入一组数据,降序排列后,删除三个连续元素的中间值
- C++类中的static数据成员,static成员函数
- C++编程新思维中的技巧
- C++使用纯虚函数完成正方形和圆形的求面积运算。
- 大话设计模式--解释器模式 interpreter -- C++实现实例
- 大话设计模式--解释器模式 interpreter -- C++实现实例
- C++求最大公约数
- mutable of C++
- C/C++数组指针与指针数组详解
- C/C++数组指针与指针数组详解
- C++求斐波那契数
- 动态分配二维数组 c++
- 常量指针补充
- c c++ 混合编译
- 2013C++第9周项目——多分支结构程序设计
- C++纯虚函数与抽象类
- c语言 常用知识点
- 集合:求A、B两个集合的交集、并集和补集的代码(C语言)
- C++在多重继承中调用虚函数
- C++函数声明时在后面加const的作用