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

How come std::strcpy still works for an destination like char copyTo[0]?

这个测试居然通过了,看来目的地的大小并不重要,只要它是一个指向char数组的有效指针即可。

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

#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;
}

I actually expected the test to fail

为什么?

任何类型的失败都意味着以下两种情况之一:

  • 由于未定义的行为导致崩溃

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

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

[...] it seems that the size of the destination doesn't matter, as long as it is a valid pointer to a char array

对于要编译的代码和运行? 。代码是well-formed? 没有.

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

记住 - 你不能期望任何东西来自展示未定义的行为.

不起作用。或者也许是这样。 Undefined Behavior (UB)就是这样,允许任何事情发生。


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

不过,假设 zero-sized 数组确实有 0 个元素,访问任何成员都是 UB。

并且由于 std::strcpy() 盲目地相信第二个参数指向一个字符串,而第一个参数指向一个足够大的缓冲区来存储包括终止 null 的副本,显然你写的元素多于零。

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