我了解了函数-strncpy_s((,它被称为字符串副本的安全版本。比函数strcpy((和strncpy((更安全。
strncpy_s((在该链接中有更多描述-https://en.cppreference.com/w/c/string/byte/strncpy
我想在我的代码库中使用这个函数-strncpy_s((来处理所有可能的情况,其中它的老兄弟通常无法处理,比如srcString比destString长。或者如果srcString不是以NULL结尾。
所以我想知道strncpy_s((的用法应该是-吗
strncpy_s(destString, sizeof(destString), srcString, (sizeof(srcString)>sizeof(destString)?(sizeof(destString)-1):(sizeof(srcString)-1)));
-[1]
优雅地处理所有可能的场景-即
- 如果srcString大于destString,则截断srcString到长度destString
- 当destString大于srcString时,则复制整个内容的srcString到destString,终止为NULL
- 当srcString和destString的长度相同时,则复制整个终止为NULL的srcString到destString的内容
- 当srcString不是NULL时终止。如果srcString小于destString然后将srcString内容的一部分复制到终止为NULL的destString。如果destString小于srcString然后从destString大小的srcString中复制内容
有人能想到上面提到的strncpy_s(([1]的用法在任何情况下都可能失败吗?我想不出来?
编辑:我已经更新了在场景中采取的行动-(2(、(3(和(4(
您根本不应该使用strncpy_s
;它是附录K函数之一,从未作为任何C库的集成部分实现(Microsoft的编译器实现了一组具有相似名称和不同语义的重叠函数(,目前正在考虑将从标准中删除。(有关这方面的更多信息,请参阅这个旧答案及其链接到的各种文档。(
相反,您应该编写自己的函数,该函数使用strlen
、memmove
和离散逻辑的组合来实现您想要的行为。您说当目标缓冲区太小时,您希望截断字符串。当目标缓冲区至少足够大时,你不会说你想发生什么,但显而易见的是复制整个字符串并停止。当srcString
不是NUL终止时,你也不会说你想发生什么,但在这种情况下,正确的做法是崩溃(请参阅《老新事物》中的这篇关于为什么的旧文章-很抱歉没有断段,请在中间的某个地方寻找"你应该崩溃"(。因此:
void safe_strncpy(char *dest, size_t destsz, char *src)
{
size_t srcsz = strlen(src); // crash here if not nul-terminated
if (srcsz > destsz - 1)
srcsz = destsz - 1;
memmove(dest, src, srcsz); // memmove is safe if dest and src overlap
dest[srcsz] = ' ';
}
像调用strcpy
一样调用,但也提供目标缓冲区的大小。请记住,目标缓冲区的大小是,而不是它可能在程序早期包含的任何字符串的大小。目标缓冲区的大小是您用其声明的大小(如果是变量(或传递给malloc
的大小(如是堆分配(。
我强烈同意@zwol关于不使用strncpy_s()
的说法。
我想提供替代代码来满足OP的目标。
- 当srcString大于destString时,将srcStrings截断为destString长度
我也不检查destsz
元素之外的srcString
数据。这样做的副作用是在destsz
之外的srcString
中不需要空字符。
- 当srcString和destString的长度相同时
- 当srcString不是
NULL时NULL字符终止
特别是,在返回值中返回故障的明确指示
在dest != NULL
和dest > 0
的所有情况下,dest
都将指向一个字符串,该字符串带有空字符。
下面的代码不仅解决了OP的问题,还通过使用memmove()
处理缓冲区重叠的情况。
// Return error flag
bool sf_strncpy(char *dest, size_t destsz, const char *src) {
// Optional pointer test
if (dest == NULL) return true;
// Size test
if (destsz == 0) return true;
// Optional pointer test
if (src == NULL) ( dest[0] = ' '; return true; }
// Look for null character, but not beyond destsz
const char *end = memchr(src, ' ', destsz);
if (end == NULL) {
memmove(dest, src, destsz - 1);
dest[destsz - 1] = ' ';
return true;
}
memmove(dest, src, end - src);
return false;
}