c-正确使用strncpy_s()-安全字符串副本-来处理所有可能的角落情况应该是什么



我了解了函数-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]

优雅地处理所有可能的场景-即

  1. 如果srcString大于destString,则截断srcString到长度destString
  2. 当destString大于srcString时,则复制整个内容的srcString到destString,终止为NULL
  3. 当srcString和destString的长度相同时,则复制整个终止为NULL的srcString到destString的内容
  4. 当srcString不是NULL时终止。如果srcString小于destString然后将srcString内容的一部分复制到终止为NULL的destString。如果destString小于srcString然后从destString大小的srcString中复制内容

有人能想到上面提到的strncpy_s(([1]的用法在任何情况下都可能失败吗?我想不出来?

编辑:我已经更新了在场景中采取的行动-(2(、(3(和(4(

您根本不应该使用strncpy_s;它是附录K函数之一,从未作为任何C库的集成部分实现(Microsoft的编译器实现了一组具有相似名称和不同语义的重叠函数(,目前正在考虑将从标准中删除。(有关这方面的更多信息,请参阅这个旧答案及其链接到的各种文档。(

相反,您应该编写自己的函数,该函数使用strlenmemmove和离散逻辑的组合来实现您想要的行为。您说当目标缓冲区太小时,您希望截断字符串。当目标缓冲区至少足够大时,你不会说你想发生什么,但显而易见的是复制整个字符串并停止。当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的目标。

  1. 当srcString大于destString时,将srcStrings截断为destString长度

我也不检查destsz元素之外的srcString数据。这样做的副作用是在destsz之外的srcString中不需要空字符

当destString大于srcString时,
  1. 当srcString和destString的长度相同时
  2. 当srcString不是NULL时NULL字符终止

特别是,在返回值中返回故障的明确指示
dest != NULLdest > 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;
}

最新更新