为什么在遗留strcpy()中没有健全性检查

以下是传统系统中最流行的strcpy实现。 为什么在开始时没有检查dest和src是否为NULL? 我曾经听说过,在过去,记忆力有限,所以短代码总是首选。 你现在可以在开始时用NULL指针检查实现strcpy和其他类似的函数吗? 为什么不?

char *strcpy(char *dest, const char *src) { char *save = dest; while(*dest++ = *src++); return save; } 

NULL是一个错误的指针,但(char*)0x1 。 它还应该检查吗? 在我看来(我不知道明确的原因),在这种低级别的操作中进行健全性检查是不必要的。 strcpy()非常基础,它应该被视为asm指令,如果需要,你应该在调用者中进行自己的健全性检查。 只是我的2美分:)

没有健全性检查,因为C最重要的潜在意识形态之一就是开发人员提供了理智。 当您假设开发人员理智时,您最终会得到一种语言,可以用来做任何事情,任何地方。

这不是一个明确规定的目标 – 很可能有人想出一个可以检查这个的实现,等等。 也许他们有。 但我怀疑许多习惯于C的人会吵着要使用它,因为如果他们的代码有可能被移植到更常见的实现中,他们还是需要进行检查。

整个C语言都写着“如果程序员知道他在做什么,我们会正确行事”。 程序员应该知道他需要做出的所有检查。 它不只是检查NULL,它确保dest指向足够的分配内存来保存src ,它检查fopen的返回值以确保文件确实打开成功,知道memcpy何时是安全的以及何时需要memmove ,等等上。

获取strcpy检查NULL不会改变语言范例。 您仍然需要确保dest指向足够的空间 – 这是strcpy在不更改接口的情况下无法检查的内容。 您还需要确保src'\0'终止,再次strcpy无法检查。

有一些C标准库函数检查NULL:例如, free(NULL)总是安全的。 但总的来说,C希望你知道你在做什么。

[C ++通常避免使用库来支持std::string和朋友。

  1. 通常情况下,库让调用者决定它想要的失败语义是什么。 如果任一参数为NULL你会有strcpy做什么? 默默地什么都不做? assert失败(在非调试版本中不是一个选项)?

  2. 选择加入比选择退出更容易。strcpy周围编写自己的包装器是很简单的,它可以validation输入并使用它。 但是,如果库本身就这样做了,那么除了重新执行strcpy ,你无法选择不执行那些检查。 (例如,您可能已经知道传递给strcpy的参数不是NULL ,如果您在紧密循环中调用它或者担心最小化功耗,它可能是您关心的事情。)通常,最好是在给予更多自由方面犯错(即使这种自由带来了额外的责任)。

最可能的原因是:因为没有指定strcpy使用NULL输入(即在这种情况下它的行为是未定义的)。

那么,如果传入NULL库实现者应该选择做什么? 我认为最好的办法是让应用程序崩溃。 可以这样想:崩溃是一个相当明显的迹象,表明出现了问题……另一方面,默默地忽略NULL输入可能会掩盖一个难以检测的错误。

没有实现NULL检查,因为C的最早目标支持强内存保护。 当进程尝试读取或写入NULL时,内存控制器将向CPU发出信号,表示尝试了超出范围的内存访问(分段违例),并且内核将终止违规进程。

这是一个很好的答案,因为尝试读取或写入NULL指针的代码被破坏了; 唯一的答案是重新编写代码以检查来自malloc(3)和朋友的返回值并采取纠正措施。 当您尝试使用指向未分配内存的指针时,就如何解决这种情况做出正确的决定为时已晚。

您应该将C标准库函数视为汇编代码上方最薄的附加抽象层,您不希望这些抽象层可以将您的东西推到门外。 除此之外的一切,如错误检查,都是您的责任。

据我所知,你想要定义的任何函数都有一个前置条件和一个后置条件。 照顾前提条件永远不应成为function的一部分。 以下是使用手册页中的strcpy的前提条件。

strcpy()函数将src指向的字符串(包括终止的’\ 0’字符)复制到dest指向的数组。 字符串可能不重叠,目标字符串dest必须足够大才能接收副本。

现在,如果不满足前提条件,那么事情可能是未定义的。

我现在是否会在strcpy中包含NULL检查。 我宁愿有另一个safe_strcpy,给安全性优先级我肯定会包括NULL检查和处理溢出条件。 因此我的前提条件得到修改。

根本没有为它定义错误语义。 特别是strcpy无法返回错误值。 C99简单地说:

strcpy函数返回s1的值。

因此,对于符合要求的实现,甚至不可能返回出错的信息。 那么为什么要烦恼呢。

我认为所有这些都是自愿的,因为strcpy被大多数编译器直接用非常高效的汇编程序取代。 错误检查取决于调用者。