我正在学习C以及将整数转换为字符串的基本示例(您在其他语言中认为这是理所当然的)。我找到的答案是这样的:
sprintf(str, "%d", num);
但我想看看这是如何实现的。所以我查看sprintf,它带我到这里:
#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
int
__sprintf (char *s, const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vsprintf (s, format, arg);
va_end (arg);
return done;
}
那么我查找_IO_vsprintf
,它显示:
int
__IO_vsprintf (char *string, const char *format, va_list args)
{
_IO_strfile sf;
int ret;
#ifdef _IO_MTSAFE_IO
sf._sbf._f._lock = NULL;
#endif
_IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
_IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
_IO_str_init_static_internal (&sf, string, -1, string);
ret = _IO_vfprintf (&sf._sbf._f, format, args);
_IO_putc_unlocked ('\0', &sf._sbf._f);
return ret;
}
这似乎围绕着_IO_vfprintf
。但我无法找到code中的位置。谷歌和GitHub没有带来任何结果。想知道是否有人可以完全实现sprintf,如果没有,可以解释它是如何工作的。
我想知道如何实现itoa,因为sprintf做到了,这听起来像是一个很好的实现。
如果没有实现,我很困惑这个代码如何实际运行。
像Looks这样的_IO_vfprintf
是_IO_vfprintf_internal
隐藏的别名。
在为正常(非宽)字符编译文件vfprintf.c
文件时,fprintf
变为一个定义为_IO_vfprintf_internal
的宏,来自here并且在别名here之前未定义。
所以_IO_vfprintf_internal
声明开始here,其中vfprintf
被声明(好吧,“在未经过处理的源文件中”,标识符vfprintf
得到的永远不会被声明)。
在vfprintf
函数停止处理所有宽度,空格,缩小和其他格式说明符之后,它最终将跳过jump tables(这基本上是通过跳转表跳转到不同的goto
标签的智能方式,其中地址通过GCC扩展labels as values获得)它将落在form_integer:
标签上。从那里我们jump到number:
。从那里我们称之为_itoa_word
。
现在_itoa_word显然简单易行,甚至足以在这里发布预处理函数:
char *
_itoa_word (_ITOA_WORD_TYPE value, char *buflim,
unsigned int base, int upper_case) {
const char *digits = (upper_case
? _itoa_upper_digits
: _itoa_lower_digits);
...
switch (base)
{
...
// SPECIAL (10); expands to:
case 10:
do
*--buflim = digits[value % Base];
while ((value /= Base) != 0);
break;
...
}
...
}
digits
,如_itoa_upper_digits或_itoa_lower_digits中的_itoa_word
是一个简单的查找表,从字符串文字初始化的char数组,用于将小数转换为其关联的ascii表示。
在outputted之后有一些代码用于处理左对齐字符串,打印前导符号字符并用空格或零填充字符串,但最后我们的字符串得到outputted(或左对齐printf("%+- 3lld %+- 4.3Lf %-+04hhd %+- 5zd", 1llu, 2.L, 3, (ssize_t)4);
)。
将整数转换为字符串的示例
所以99%的工作都是为了处理所有奇怪的事情
#include <stdio.h>
char *my_itoa(char *dest, size_t destlen, int number)
{
// we will work our way from the ending
char *p = &dest[destlen];
// null terminate the string
*--p = '\0';
while (number) {
if (p == dest) {
// destination buffer too small!!
return NULL;
}
*--p = "0123456789"[number % 10];
number /= 10;
}
return p;
}
int main()
{
char buf[20];
printf("%s\n", my_itoa(buf, sizeof(buf), 123));
}
它需要符合的格式说明符。转换只是一个简单的转换,使用查找字符串(处理非ASCII系统),它的工作方式是向后通过数字:
qazxswpoi