【问题标题】:Wrong behavior of the char arrays after strncpystrncpy 后 char 数组的错误行为
【发布时间】:2020-02-17 21:45:46
【问题描述】:

我不是 C 开发人员,我可能会出错(我正在对旧代码进行更改):

有一个名为strncpySafe 的函数(正如我所见,它只是strncpy 的一个包装器):

void    strncpySafe(char *strDest, const char *strSource, int count)
{
    strncpy(strDest, strSource, count-1);
    strDest[count-1] = '\0';
}

步骤本身,其中是从源 A 到源 B 的一个带有偏移量的副本:

void Foo(const char *message) {
char line[1024];
...
strncpySafe(line, &message[message_offset], count);

在最后一步中,他们正在修改复制的 line[]message[] 应该保持不变):

line[N] = 0;

在最后一步,我可以从 VSCode 调试器中看到 line[N] 正在更改,同时 message[N] 也进行了修改。
我正在使用Ubuntu /g++-8, -march=x86-64, -std=c++11
是关于相同的指针吗?是 strncpy 的错误用法吗?
谢谢。

ps:在 windows 和 linux 的游戏客户端中使用了相同的代码,我可以说在 windows 上它没有被复制(windows 是在较旧的 c 编译器上构建的,没有使用相同的 c ++11 尚未构建)。

编辑:为了清楚起见,linemessage 的修改发生在我通过line[N] = 0; 的一步的同时发生

删除了 message_offset_2 的错误命名。这是一个count
让我提供一个执行示例:

strncpySafe(line, &message[5], 10); // It copies 10 elements from 5th
line[5] = 0; // this leads that message[5] also gets 0 for it's element

边界没有错误(偏移量和计数器似乎没问题)。

我同意此代码已被弃用并且逻辑可能不清楚(为什么要这样做),我可以使用std::string。对我来说,这很有趣。

【问题讨论】:

  • [Tangent] 如果您使用 C++,为什么不使用std::string 来管理您的字符串对象。它使这样的代码不再需要。
  • @gorZ 提供一个演示问题的最小完整程序
  • strncpySafe 正在将 count-1 字符从源复制到目标。 line[message_offset_2] = 0; 正在向目标添加终止,但不需要,如果您更新 strncpy 以复制直到 count 或传递 offset+1(取决于计数器的使用方式)
  • 你是说line的字符被修改了,message的字符也被修改了——通过samestrncpySafe调用?这听起来像是您传入了一个伪造的message 缓冲区,该缓冲区在调用堆栈(欠载)上有别名。或者可能 message_offset_2 大于 1024。可以assert 这样的事情。
  • @IgorZ 字符串是否重叠?

标签: c++ undefined-behavior c-strings strncpy


【解决方案1】:

考虑到您在问题中所写的数组消息也发生了变化,那么很明显您使用的函数不正确,因此您有未定义的行为。

例如,您命名为message_offset_2 的第三个参数指定应从字符串复制到目标字符数组的字符数。所以它不应该被命名为message_offset_2

未定义行为的另一个原因可能是使用重叠数组。

所以要么第三个参数指定不正确,要么字符数组发生重叠。

但无论如何,函数的声明和定义都很糟糕。

如果它是标准 C 函数 strncpy 的包装器,那么它至少应该被声明为

char * strncpySafe( char * restrict s1, const char * restrict s2, size_t n );

或者如果它被声明为 C++ 函数,那么

char * strncpySafe( char * s1, const char * s2, size_t n );

如果函数被设计为复制n 字符,那么函数的主体应该是这样的

if ( n )
{
    strncpy( s1, s2, n );
    s1[n] = '\0';
}

return s1;

因此目标数组至少应包含n + 1 元素。

And(C 标准,7.23.2.4 strncpy 函数)

如果复制发生在重叠的对象之间,则行为是 未定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多