6

线索在标题中,但基本上我继承了一些包含 800 多个 strcpy 实例的代码。我想写一个新函数,然后用 strcpy_mine 替换 strcpy。

所以我试图弄清楚 strcpy_mine 将有什么参数列表。

我试过:

void strcpy_mine( char* pTarget, const char* const pCopyMe )
{
  const unsigned int lenAlwaysFour = sizeof(pCopyMe ); //:(
  strncpy( pTarget, pCopyMe, lenAlwaysFour );

  //add extra terminator in case of overrun
  pTarget[lenAlwaysFour] = 0;
}

但 sizeof 始终为 4 pCopyMe 是一个指针

我不想做的是替换

strcpy (buf, pCopyMe);

strncpy (buf, pCopyMe, sizeof(pCopyMe)); buf[sizeof(pCopyMe)] = 0;

有任何想法吗?(strcpy_l 不可用)

4

7 回答 7

12

sizeof() 返回类型的大小——在这种情况下const char* const,在 32 位机器上为 4。

我想你认为你想要strlen()。但这不是使用 strncpy 函数的正确方法。您需要strncpy的输出缓冲区的大小。

要解决此问题,您需要检查每个调用站点的代码,并计算输出缓冲区的大小,并将其作为参数传递给strcpy_mine. 如果 strcpy(或 strcpy_mine)的调用站点不知道输出缓冲区的大小,则需要在代码中向后搜索分配缓冲区的位置,并将大小一直向下传递到 strcpy 站点.

基本上,您不能编写一个替代 strcpy 的替代品,它采用相同的参数并希望避免首先产生 strncpy 的问题(以及除此之外的更好的替代品)。您可以创建一个函数,它采用与 strncpy 相同的参数,但确保结果为空终止 - 查看OpenBSD 的 strlcpy()函数的实现。但第一步必须是更改调用站点以传递输出缓冲区大小的知识。

于 2009-06-04T15:04:17.637 回答
4

根据调用站点的外观,大多数情况通常可以通过一个简单的模板来处理:

#include <string.h>

template <int bufferSize>
void strcpy_mine( char (&pTarget)[bufferSize], const char* const pCopyMe )
{
  strncpy( pTarget, pCopyMe, bufferSize-1 );

  //add extra terminator in case of overrun
  pTarget[bufferSize-1] = 0;
}

int main()
{
  char buf[128];
  strcpy_mine(buf,"Testing");
  return 0;
}

如果您使用的是 Microsoft Visual Studio 2005 或更高版本,请参阅Microsoft 实施的安全模板重载

于 2009-06-04T19:33:06.453 回答
2

您可以为您的 strcpy_mine 使用与 strncpy 相同的参数列表,但将其编写为始终为 null 会终止结果。应该不是很难做到。

然而,一个挑战是调用 strcpy() 的一些现有代码可能也不知道缓冲区的大小。

于 2009-06-04T15:05:00.037 回答
2

可能有点外围,但由于没有人提到它并且它在标题中被标榜:你不能(合法地)编写一个名为strcpy_mine().

名称以开头的函数的“命名空间”str是为标准库保留的。例如,请参阅此问题的已接受答案

于 2009-06-04T19:41:39.633 回答
1

道格拉斯·利德说得对。替换 strcpy 的用处是有限度的,除非您愿意在每个实例中都传递一个好的、合理的缓冲区长度。这是很多工作!

好消息是,这是值得的!几年前,我参与了几个 C++ 项目,这些项目都是迟到的、有缺陷的和不可靠的。通过声明 strcpy 和 strlen 被禁止,并从项目中抽出 2-3 天用自定义 strncpy/strnlen 替换它们,在所有这些项目中,我们突然可以运行几天而不是几个小时。我们还看到屏幕显示和日志文件中出现了很多截断的字符串。这为我们提供了追踪截断问题(以前是崩溃问题)所需的线索。

如果您不想这样做,您可以通过简单地检查两个指针​​参数是否为 NULL、限制字符串副本的最大大小并记录所有达到边界的时间来获得小得多的好处。不要对任何一个参数执行 strlen,因为如果字符串没有正确地以 null 终止,strlen 会很高兴地在你身上崩溃。

如今,新项目使用良好的字符串对象,但有很多遗留代码没有。

于 2009-06-04T17:20:12.553 回答
0

您也可以使用宏来避免多次编辑。或者通过一些脚本自动编辑。

于 2009-06-04T15:33:33.223 回答
0

正如其他人在上面所说的那样,您肯定需要将目标缓冲区的大小作为参数传递。

这有点离题,但我只想指出,在你使用 之后strncpy(),你需要将缓冲区的最后一个字符设置为 null,它的索引1 小于长度(不是缓冲区的长度) :

strncpy (buf, pCopyMe, buflen); buf[buflen - 1] = '\0';

或者,您可以strncat()在一个空字符串上使用,传递一个少 1 的长度,它会保证以空值终止您的字符串:

buf[0] = '\0'; strncat (buf, pCopyMe, buflen - 1);
于 2009-06-04T16:48:26.740 回答