我正在学习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中的位置。 Google和GitHub没有任何结果。想知道是否有人可以使用sprintf的完整实现,如果没有,可以解释它的工作原理。
我想知道如何像sprintf一样实现itoa,这听起来像是一个很好的实现。
对于没有实现的情况,该代码如何实际运行感到困惑。
答案 0 :(得分:2)
Looks(例如_IO_vfprintf
)是_IO_vfprintf_internal
的隐藏别名。
在编译文件vfprintf.c
中的普通(不宽字符)文件时,fprintf
变成一个宏,定义为_IO_vfprintf_internal
,从here开始,并且在别名{{ 3}}。
因此_IO_vfprintf_internal
声明从here开始,在此声明vfprintf
(好吧,“在未经处理的源文件中”,标识符vfprintf
从未声明)。 / p>
在vfprintf
函数停止处理所有宽度,空格,负号和其他格式说明符之后,它最终将跳过here(这基本上是一种跳到不同{{1 }}(由跳转表标记),该跳转表具有通过GCC扩展名jump tables获得的地址),它将落在labels as values标签上。从那里我们form_integer:
到jump。从那里我们叫number:
。
现在_itoa_word
很简单,甚至足以在此处发布预处理功能:
goto
其中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;
...
}
...
}
(如_itoa_word或_itoa_upper_digits)是一个简单的查找表,是从字符串文字中初始化的char数组,用于将小数转换为相关的ascii表示形式
digits
之后,有一些代码用于处理字符串的左对齐,打印前导符号字符并用空格或零填充字符串,但最终我们的字符串为_itoa_lower_digits(或左对齐的{{3 }}。
将整数转换为字符串的示例
所以99%的工作是处理所有奇怪的事情
_itoa_word
它需要符合的格式说明符。转换只是使用查找字符串(以处理非ASCII系统)的简单转换,可以通过数字向后查找:
printf("%+- 3lld %+- 4.3Lf %-+04hhd %+- 5zd", 1llu, 2.L, 3, (ssize_t)4);