atoi是一个标准函数,但itoa不是。为什么?

11

为什么要区分这两者?我曾经以为itoastdlib.h中,结果导致我链接了一个带有不同参数的自定义版本的itoa并产生了一些疯狂的错误。

那么,为什么itoa不是标准函数呢?它有什么问题吗?为什么标准更倾向于它的孪生兄弟atoi


11
atoi是历史悠久的函数,而itoa则不是。你实际上不应该使用atoi,而应该使用strto(u)l(l)。对于反向转换,可以使用s(n)printf - Daniel Fischer
由于itoa不是标准函数,您能否包含您想要讨论的itoa函数的接口契约?这样做可能会回答您的问题。 - CB Bailey
@bta 许多其他标准函数(如 strcpy)存在类似的问题,但它们都在“标准”总线上! - Pavan Manjunath
@HansPassant 我在这里的POSIX规范中没有找到它 pubs.opengroup.org - Pavan Manjunath
@Stacker- 是的,但是它们每个标准中都有安全变体。原始C标准中仍有不安全的函数,但是它们已经为所有这些函数添加了安全变体。如果已知存在漏洞,则不会考虑将任何新函数添加到规范中。 - bta
显示剩余5条评论
3个回答

7

至今没有标准化的itoa方法,因此如果要将其添加到标准库中,需要有充分的理由和良好的接口。

我见过的大多数itoa接口都使用静态缓冲区,存在可重入性和生命周期问题,或者分配动态缓冲区,调用者需要释放内存,或者要求用户提供缓冲区,使接口与sprintf相比不具优势。


3
当库中没有使用 printf() 系列中的任何内容时,itoa() 与传入缓冲区一起使用可以比 s(n)printf() 更加高效。这并不是将 itoa() 放入标准 C 库的理由,但这是选择它而不是更重的东西的理由。 - Julie in Austin
@JulieinAustin:为什么这是一个巨大的胜利?确实,您不必解析两个字符格式字符串,但我不认为这是一个_巨大的_胜利。 - CB Bailey
2
所有与printf()家族一起出现的解析函数也可以避免使用。记住——除了解析格式字符串之外,生活中还有其他事情。比如内存占用。 - Julie in Austin
@JulieinAustin:你所说的“come along for the ride”是什么意思?实现时只链接标准库中使用的函数是完全没有问题的。sprintf可能比仅用于int格式化程序的工具更加复杂,但我仍然不认为这种差异是“巨大的优势”。也许我没有完全理解你所考虑的情况。 - CB Bailey
1
我想@JulieinAustin正在为一个非常受限制的目标环境编写代码,比如设备固件。这不是通常的FOSS使用方式,但对于C语言来说,这是一个至关重要的应用领域。有时在这些环境中,你不能链接到任何*printf函数。 - Spike0xff
1
@Spike0xff 猜对了——我经常进行的编码工作中,64K 仍然被认为是“巨大”的。我最后编写的一段 C 代码编译后大小为 15K,使用不到 2K 的 RAM。这是一件好事,因为该部分具有 28K 的 I-space 和 2K 的 D-space。 - Julie in Austin

2
一个“itoa”函数必须返回一个字符串。由于字符串不是一等对象,调用者必须传递一个缓冲区+长度,并且函数必须有某种方式来指示它是否已经用完了空间。在你做到这一步的时候,你已经创建了一个与sprintf足够相似的东西,没有必要复制代码/功能。 "atoi"函数存在是因为它比完整的“scanf”调用更简单(并且可以说更安全)。一个“itoa”函数不会有足够的不同来值得它。

1
并不完全是这样。多年来,许多开发人员在代码中包含了类似于itoa()的例程。最大缓冲区大小被很好地限制在16位盒子上的6个字节和一个NUL的备用空间以及32位盒子上的11个字节加一个备用空间。我在一段数据采集固件中使用itoa()函数来格式化包含版本和状态信息的文本字符串。在那个实现中,我确实传递了一个指针,但我也看到过其他的缓冲区是静态的。最好的解释是,就像标准一样,有很多不同的itoa()实现可供选择! - Julie in Austin
@JulieinAustin - 我并不是说它们不存在,只是它们没有被_标准化_。你的描述有助于说明这一点。缓冲区大小取决于机器的寄存器大小。C标准委员会避免使用硬件特定的细节。一个标准化的函数必须具有一致的接口,并在任何平台上都能正常工作,而实现这一点的唯一实际方法是重新发明大部分printf() - bta
1
我在回复你的说法,即函数必须做各种各样的事情。实际上并不需要这样做,可以使用适当数量的含糊词来规定实现,以解决字长差异的问题。我的意思是,对于任何给定的字长,都有一个被广泛理解的、有限的存储字符数,用于表示该字长下所有可能的整数值。简而言之,它可以比你所认为的更容易、更一致地实现。 - Julie in Austin

1
itoa函数不是标准函数,可能的原因是它没有一致的定义。不同的编译器和库供应商引入了略微不同版本的itoa,可能是作为atoi的补充发明的。
如果某个非标准函数被广泛提供,那么标准的工作就是将其编码:基本上是将现有函数的描述添加到标准中。如果函数具有更或多或少一致的参数约定和行为,则可以这样做。
由于已经存在多种itoa的版本,因此这种函数无法添加到ISO C中。无论描述什么行为,都会与某些实现不符。 itoa已经以以下形式存在:
void itoa(int n, char *s); /* Given in _The C Programming Language_, 1st ed. (K&R1) */

void itoa(int input, void (*subr)(char)); /* Ancient Unix library */

void itoa(int n, char *buf, int radix);
char *itoa(int in, char *buf, int radix);

微软在其Visual C运行时库中提供了一个名为_itoa的修改后名称。

C语言实现历史上不仅提供了不同定义的itoa函数,C程序也为自己提供了一个名为itoa的函数,这是可能发生冲突的另一个来源。

基本上,itoa标识符在标准化方面是“放射性”的,作为外部名称或宏。如果这样的函数被标准化,它将必须使用不同的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接