strcpy...想要替换为 strcpy_mine ,这将导致 strncpy 和 null 终止
线索就在标题中,但基本上我继承了一些具有 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 不可用)
The clue is in the title but basically I've inherited some code which has 800+ instances of strcpy. I want to write a new function and then to replace strcpy with strcpy_mine.
So I'm trying to work out what parameter list strcpy_mine will have.
I tried:
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;
}
but the sizeof is always 4 pCopyMe is a pointer
what I don't want to do is replace
strcpy (buf, pCopyMe);
with
strncpy (buf, pCopyMe, sizeof(pCopyMe)); buf[sizeof(pCopyMe)] = 0;
Any ideas? (strcpy_l isn't available)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您还可以使用宏来避免多次编辑。 或者通过某些脚本自动编辑。
Also You can use macroses for avoid multiple editings. Or automate editing via some script.
正如其他人上面所说,您肯定需要传入目标缓冲区的大小作为参数。
这是有点题外话,但我只想指出,在使用
strncpy()
后,您需要将缓冲区的最后一个字符设置为 null,该字符的索引为 比长度少 1(不是缓冲区的长度):或者,您可以对空字符串使用
strncat()
,向其传递一个少 1 的长度,并且它将保证以空终止您的字符串:You definitely need to pass in the size of the destination buffer as a parameter, as other people have said above.
This is kind of off-topic, but I just want to point out that, after you use
strncpy()
, you need to set to null the last character of the buffer, which has index 1 less than the length (not the length of the buffer):Or alternatively, you can use
strncat()
on an empty string, passing it a length that is 1 less, and it will guarantee to null-terminate your string:sizeof() 返回类型的大小 - 在本例中
const char* const
在 32 位机器上将为 4。我想你认为你想要
strlen()
。 但这不是使用 strncpy 函数的正确方法。您需要 strncpy 的输出缓冲区的大小。
要解决此问题,您需要检查每个调用站点的代码,计算出输出缓冲区的大小,并将其作为参数传递给
strcpy_mine
。 如果 strcpy (或 strcpy_mine)的调用站点不知道输出缓冲区的大小,则需要在代码中向后搜索分配缓冲区的位置,并将大小一直传递到 strcpy 站点。基本上,您不能编写一个带有相同参数的 strcpy 替代品,并希望避免首先产生 strncpy 的问题(以及除此之外更好的替代品)。 您可以创建一个采用与 strncpy 相同参数的函数,但确保结果以 null 终止 - 查看 OpenBSD 的 strlcpy() 函数。 但第一步必须是更改调用站点以传递输出缓冲区大小的信息。
sizeof() returns the size of the type - in this case
const char* const
which will be 4 on 32-bit machines.I think you think you want
strlen()
. But that isn't the right way to use strncpy functions.You need the size of the output buffer for strncpy.
To fix this you need to examine the code at each call site, and work out the size of the output buffer, and pass that as an argument to
strcpy_mine
. If the call-site for strcpy (or strcpy_mine) doesn't know the size of the output buffer, you need to search backwards in the code for the location that allocates the buffer, and pass the size all the way down to the strcpy site.Basically you can't write a drop in replacement for strcpy that takes the same arguments and hope to avoid the problems that produced strncpy in the first place (and better replacements beyond that). You can create a function that takes the same arguments as strncpy, but ensures the result is null-terminated - look at the implementation of OpenBSD's strlcpy() function. But the first step has to be to change the calling sites to pass on knowledge of the output buffer size.
根据调用站点的外观,大多数情况通常可以通过简单的模板来处理:
如果您使用的是 Microsoft Visual Studio 2005 或更高版本,请参阅 用于 Microsoft 实现的安全模板重载。
Depending on how the call-sites look like, often majority of cases can be handled by a simple template:
If you are using Microsoft Visual Studio 2005 or newer, see Secure Template Overloads for a Microsoft implementation.
您可以为 strcpy_mine 使用与 strncpy 相同的参数列表,但将其写入以使其始终为 null 终止结果。 应该不是很难做到的。
然而,一个挑战是,某些调用 strcpy() 的现有代码可能也不知道缓冲区的大小。
You could use the same parameter list as strncpy for your strcpy_mine, but write it so that it always null terminates the result. Shouldn't be very hard to do.
One challenge, however, is that some of your existing code that calls strcpy() may not know the size of the buffer, either.
也许有点外围,但因为没有人提到它并且它在标题中炫耀:你不能(合法地)编写一个名为
strcpy_mine()
的全局函数。名称以
str
开头的函数的“命名空间”是为标准库保留的。 例如,请参阅对此的接受答案问题。Slightly peripheral perhaps, but since noone mentioned it and it's flaunted in the title: you can't (legally) write a global function called
strcpy_mine()
.The "namespace" of functions whose names start with
str
is reserved for the standard library. See, for instance, the accepted answer to this question.道格拉斯·利德说得对。 替换 strcpy 的用处是有限的,除非您愿意做繁重的工作,在每个实例中传递一个良好的、合理的缓冲区长度。 这是很多工作!
好消息是,这是值得的! 几年前,我参与了几个 C++ 项目,这些项目迟到、有缺陷且不可靠。 通过声明禁止 strcpy 和 strlen,并在项目中花费 2-3 天的时间将它们替换为自定义的 strncpy/strnlen,在所有这些项目中,我们突然可以运行几天而不是几个小时。 我们还看到屏幕显示和日志文件中出现了大量被截断的字符串。 这为我们提供了追踪截断问题(以前的崩溃问题)所需的线索。
如果您不想这样做,只需检查两个指针参数是否为 NULL,并限制字符串副本的最大大小并记录所有到达边界的时间,即可获得较小的好处。 不要对任一参数执行 strlen,因为如果字符串未正确以 null 结尾,strlen 会很高兴地崩溃。
如今,新项目使用了良好的字符串对象,但有很多遗留代码没有使用。
Douglas Leeder has it right. There is a limit to the usefulness of replacing strcpy unless you are willing to do the grunt work of passing in a good, sane buffer length at each and every instance. That's a lot of work!
The good news is, it is worth it! Back a few years ago, I came in on several C++ projects that were late, buggy, and unreliable. By declaring strcpy and strlen forbidden, and taking 2-3 days out of the project to replace them with custom strncpy/strnlen, in all these projects we suddenly could run for days instead of hours. We also saw a lot of truncated strings come out on screen displays and log files. That gave us the clues needed to track down the truncation issues, formerly crashing issues.
If you do not want to do this, you can get a much smaller benefit by simply checking both pointer parameters for NULL, and limiting the maximum size of a string copy and logging all times that the boundary is reached. Do not do a strlen of either parameter, as strlen will happily crash on you if the string is not properly null terminated.
Nowadays, new projects use good string objects, but there is a lot of legacy code out there that does not.