为啥 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地?

Posted

技术标签:

【中文标题】为啥 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地?【英文标题】:How come std::strcpy still works for an destination like char copyTo[0]?为什么 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地? 【发布时间】:2019-06-22 23:56:16 【问题描述】:

这个测试实际上通过了,看来目的地的大小无关紧要,只要是指向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;

【问题讨论】:

当代码有这样的错误时,它通常不会像你期望的那样。这就是为什么避免这样的错误很重要。我还要注意,您在代码中的评论说“它有效”。你为什么要描述你不期望的行为作为代码工作?通常,我们说代码在执行我们期望的事情时有效,而不是在执行与我们预期不同的事情时。 另请注意,char copyTo[0]; 首先不是一个有效的定义:不允许使用大小为零的原始数组。 【参考方案1】:

我实际上预计测试会失败

为什么?

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

由于未定义的行为而崩溃

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

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

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

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

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

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

【讨论】:

【参考方案2】:

它不工作。或者也许确实如此。 Undefined Behavior (UB) 就是这样,允许任何事情发生。


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

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

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

顺便说一句,您必须包含&lt;cstring&gt;,而不应包含using namespace std;

【讨论】:

以上是关于为啥 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我仍然可以在字符串范围之外访问 std::string::c_str() 返回的 char 指针? [复制]

为啥将字符串作为文件名而不是 char* 传递时出现错误?

为啥 2019 年我们仍然不能使用 ctypes 从 Python 调用 C++?

为啥指针分配的内存在函数之后仍然存在,而不是数组?

java 8 String.chars() 是不是适用于 8 字节字符?

为啥我的 charFormat 样式仅适用于选择,并且仅适用于特定方向的选择?