strcpy... 想用 strcpy_mine 替换,它将 strncpy 和 null 终止
Posted
技术标签:
【中文标题】strcpy... 想用 strcpy_mine 替换,它将 strncpy 和 null 终止【英文标题】:strcpy... want to replace with strcpy_mine which will strncpy and null terminate 【发布时间】:2010-10-31 08:51:55 【问题描述】:线索在标题中,但基本上我继承了一些包含 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 不可用)
【问题讨论】:
【参考方案1】:sizeof() 返回类型的大小 - 在这种情况下 const char* const
在 32 位机器上为 4。
我想你认为你想要strlen()
。但这不是使用 strncpy 函数的正确方法。
您需要 strncpy 的 输出 缓冲区的大小。
要解决此问题,您需要检查每个调用站点的代码,计算输出缓冲区的大小,并将其作为参数传递给strcpy_mine
。如果 strcpy(或 strcpy_mine)的调用站点不知道输出缓冲区的大小,则需要在代码中向后搜索分配缓冲区的位置,并将大小一直向下传递到 strcpy 站点.
基本上,您不能编写一个替代 strcpy 的替代品,它采用相同的参数并希望避免首先产生 strncpy 的问题(以及除此之外的更好的替代品)。您可以创建一个函数,它采用与 strncpy 相同的参数,但确保结果以空值结尾 - 查看 OpenBSD's strlcpy() 函数的实现。但第一步必须是更改调用站点以传递有关输出缓冲区大小的信息。
【讨论】:
+1 表示 strlcpy。在编写与此类似的我自己的函数时,我还将枚举 AllOrNothing, TruncateOkay 传递给函数以使其处理溢出情况。【参考方案2】:根据调用站点的外观,大多数情况通常可以通过简单的模板处理:
#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 或更高版本,请参阅 Secure Template Overloads 了解 Microsoft 实施。
【讨论】:
干杯!这几乎是我所追求的,但它仍然迫使我通过 char buf[200] 将缓冲区的大小放在人字形中。 strcpy_mine(buf, pString); strCpyMine您可以为您的 strcpy_mine 使用与 strncpy 相同的参数列表,但将其编写为始终为 null 以终止结果。应该不会很难做到。
然而,一个挑战是,调用 strcpy() 的某些现有代码可能也不知道缓冲区的大小。
【讨论】:
我支持这个。您需要为输出缓冲区的大小添加另一个参数。 strcpy 方法是缓冲区溢出错误的典型来源。微软甚至弃用了这个函数,取而代之的是 strncpy。【参考方案4】:也许有点外围,但因为没有人提到它并且在标题中标榜:你不能(合法地)编写一个名为 strcpy_mine()
的全局函数。
名称以str
开头的函数的“命名空间”是为标准库保留的。例如,请参阅the accepted answer to this question。
【讨论】:
【参考方案5】:道格拉斯·利德说得对。替换 strcpy 的用处是有限度的,除非您愿意在每个实例中都传递一个良好、合理的缓冲区长度。工作量很大!
好消息是,这是值得的!几年前,我参与了几个 C++ 项目,这些项目都是迟到的、有缺陷的和不可靠的。通过声明 strcpy 和 strlen 被禁止,并从项目中抽出 2-3 天用自定义 strncpy/strnlen 替换它们,在所有这些项目中,我们突然可以运行几天而不是几个小时。我们还看到屏幕显示和日志文件中出现了很多截断的字符串。这为我们提供了追踪截断问题(以前是崩溃问题)所需的线索。
如果您不想这样做,您可以通过简单地检查两个指针参数是否为 NULL、限制字符串副本的最大大小和 记录所有达到边界的时间来获得小得多的好处。 不要使用任何一个参数的 strlen,因为如果字符串没有正确地以 null 终止,strlen 会很高兴地崩溃。
现在,新项目使用良好的字符串对象,但有很多旧代码不使用。
【讨论】:
【参考方案6】:您还可以使用宏来避免多次编辑。或者通过一些脚本自动编辑。
【讨论】:
如果你关心,宏是单数,宏是复数。 Macroses不是一个词。我猜英语不是你的母语。我只是想帮你。【参考方案7】:正如其他人在上面所说的那样,您肯定需要将目标缓冲区的大小作为参数传递。
这有点离题,但我只想指出,在您使用strncpy()
之后,您需要将缓冲区的最后一个字符设置为空,该字符的索引少1 em> 比长度(不是缓冲区的长度):
strncpy (buf, pCopyMe, buflen); buf[buflen - 1] = '\0';
或者,您可以在一个空字符串上使用strncat()
,将其长度减少1,它会保证您的字符串以空值结尾:
buf[0] = '\0'; strncat (buf, pCopyMe, buflen - 1);
【讨论】:
如果你仍然在它为什么不: strncpy(buf, pCopyMe, buflen)[buflen-1]='\0'; :-)以上是关于strcpy... 想用 strcpy_mine 替换,它将 strncpy 和 null 终止的主要内容,如果未能解决你的问题,请参考以下文章