为啥 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 的副本,因此显然您写入的元素不止零。
顺便说一句,您必须包含<cstring>
,而不应包含using namespace std;
。
【讨论】:
以上是关于为啥 std::strcpy 仍然适用于 char copyTo[0] 之类的目的地?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我仍然可以在字符串范围之外访问 std::string::c_str() 返回的 char 指针? [复制]
为啥 2019 年我们仍然不能使用 ctypes 从 Python 调用 C++?