strncpy_s不尊重标准?

strncpy_s does not respect the standard?

我的代码在 Visual Studio 2010 上运行良好:

std::string s = "Ceci est le test du StrnCpy";
char buffer_standard[5];
strncpy( buffer_standard, s.c_str(), 5 );
assert( strncmp( buffer_standard, "Ceci ", 5 ) == 0 );

但是,编译器报告 strncpy 不安全,因为我不想设置 _CRT_SECURE_NO_WARNINGS(因为它们可能是正确的,不安全),我尝试使用 MSDN strncpy_s 版本. 但它的行为方式不同!!!

这会引发断言(缓冲区太小),因此您必须调整大小参数:

std::string s = "Ceci est le test du StrnCpy";
char buffer_msdn[5];
strncpy_s( buffer_msdn, s.c_str(), 5 );

所以我尝试了这个,但是 buffer_msdn[4] 是 '\0' 而不是 ' ':

std::string s = "Ceci est le test du StrnCpy";
char buffer_msdn[5];
strncpy_s( buffer_msdn, s.c_str(), 5-1 );
assert( strncmp( buffer_msdn, "Ceci ", 5 ) == 0 ); // asserts!

这同样失败了:

strncpy_s( buffer_msdn, sc.c_str(), _TRUNCATE );

额外字符的处理方式不同:

std::string s = "Ceci";
char buffer_standard[20];
strncpy( buffer_standard, s.c_str(), 20 );

char buffer_msdn[20];
strncpy_s( buffer_msdn, s.c_str(), s.size() );

buffer_standard 是 "Ceci" 后跟 16 '\0' buffer_msdn是"Ceci"后面只有一个'\0'(那就是垃圾)

那么,Microsoft 如何期望我们用 strncpy_s 替换具有相同行为的 strncpy???

how does Microsoft expects us to replace strncpy by strncpy_s with the same behaviour?

如果他们有相同的行为,他们将不可避免地遇到相同的安全问题:可能无法终止。 strncpy 接受的参数优先于 NUL 终止复制更多源数据,新功能基本上考虑了该选择对保证警告提示很重要的情况:

  • 代码更改为:
    • 显示程序员对少复制一个源字符感到高兴,或者,
    • 调整目标缓冲区的大小以接受额外的字符,否则
  • 移动到另一个函数,例如 memcpy(可能需要额外事先调用 strlen().size())或坚持使用 strncpy(可能使用 _CRT_SECURE_NO_WARNINGS).

由于这些函数专门支持 ASCIIZ 字符串 - 其中仅要求一个尾随 NUL - 偶尔使用最后一个选项的不便显然被认为是可以接受的。