为什么 std::strcpy 仍然适用于像 char copyTo[0] 这样的目的地?



这个测试实际上通过了,似乎目标的大小无关紧要,只要它是指向字符数组的有效指针即可。

我实际上预计测试会失败,任何解释将不胜感激。

#include "gtest/gtest.h"
#include <string>
using namespace std;
TEST(practice, book) {
const char * copyFrom = "Hello World!";
char copyTo[0]; //TODO: why it works?
std::strcpy(copyTo, copyFrom);
EXPECT_STREQ("Hello World!", copyTo);
std::cout << copyTo << std::endl;
}

我实际上预计测试会失败

为什么?

任何类型的失败都意味着以下两件事之一:

  • 由于未定义的行为而崩溃

  • std::strcpy引发的其他错误对其参数进行了一些检查

std::strcpy不会对其参数执行任何检查(由于性能原因),并且它明确指出尝试使用它写入不够大的缓冲区是未定义的行为。这意味着崩溃(或其他故障迹象)也可能发生,但由于未定义的行为,而不是由于某些确定缓冲区不正确的诊断。

[...]似乎目的地的大小无关紧要,只要它是指向char数组的有效指针即可。

要编译和运行代码?是的。为了使代码格式正确?没有

您的代码表现出未定义的行为,并且无法预测其结果。它可能看起来有效,它可能崩溃,它似乎只在星期五工作,或者它可以开始无限地输出东西到标准输出。

请记住 - 你不能期望从表现出未定义行为的代码中获得任何东西。

它不起作用。或者也许确实如此。未定义行为(UB)就是这样,允许任何事情发生。


无论如何,原始数组必须具有正大小,这是引入std::array的原因之一。如果您的编译器允许零大小的数组作为扩展,则这超出了标准。

不过,假设一个零大小的数组确实有 0 个元素,访问任何成员都是 UB。

由于std::strcpy()盲目地相信第二个参数指向一个字符串,而第一个参数指向一个足够大小的缓冲区来存储包含终止 null 的副本,因此您显然正在写入超过零个元素。

顺便说一句,您必须包括<cstring>,并且不应该using namespace std;

最新更新