如何使用strncpy_s()函数实现strncpy()功能?

sha*_*oth 7 c++ string visual-c++

在某些情况下我真的需要strncpy()功能 - 例如我在预定义的接口中有一个函数,它传递缓冲区的地址和缓冲区的大小:

HRESULT someFunction( char* buffer, size_t length );
Run Code Online (Sandbox Code Playgroud)

并且记录了我可以复制一个以空格终止的字符串,其长度不超过length- 如果它完全是长度length我不会空终止字符串并且调用者知道字符串以空字符结束或在长度length以先发生者为准,一切正常.

我当然会用strncpy()

HRESULT someFunction( char* buffer, size_t length )
{
    const char* toCopy = ...
    size_t actualLength = strlen( toCopy );
    if( actualLength > length ) {
        return E_UNEXPECTED; // doesn't fit, can't do anything reasonable 
    }
    strncpy( buffer, toCopy, length );
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)

现在我有了这段代码,需要将它从Visual C++ 7迁移到Visual C++ 9.我编译它并看到一个strncpy()不安全的警告,我应该使用strncpy_s().

strncpy_s()设计为始终空终止缓冲区,因此我无法在上述场景中将其用作直接替换.我将不得不E_UNEXPECTED在字符串上返回length - 1(不像length以前那样),或者只要字符串为length或更长时间,或者程序将运行到未定义的行为,它就会触发无效的参数错误处理程序.

到目前为止我应用的解决方案是只定义一个_CRT_SECURE_NO_WARNINGS并使编译器闭嘴.

有什么办法可以strncpy_s()作为实际的替代品strncpy()吗?

Ste*_*fan 5

您在这里面临的问题是您的函数本身是不安全的,就像strncpy()是。这是不安全的,因为您的函数的调用者可能会忘记返回的字符串不是空终止的。如果这确实是您的函数所需的行为,我建议不要_CRT_SECURE_NO_WARNINGS全局定义和禁用警告,而是使用#pragmas

// document here exactly why you can not use strncpy_s
#pragma warning( push )
#pragma warning( disable : 4996 )
// your code that uses strncpy instead of strncpy_s
#pragma warning( pop ) 
Run Code Online (Sandbox Code Playgroud)

这样,您只能在绝对必须使用不安全功能的情况下禁用这些警告。


sha*_*oth 2

尝试将str*cpy*()函数用于具有固定目标缓冲区的场景是一种常见的误解。这里的意思是这些函数“复制直到出现空字符或其他条件”。在这种情况下,有这样的代码:

size_t actualLength = strlen( toCopy );
if( actualLength > length ) {
    return E_UNEXPECTED; // doesn't fit, can't do anything reasonable 
}
Run Code Online (Sandbox Code Playgroud)

因此代码在继续复制之前就知道实际的字符串长度。一旦长度已知,只有使用它memcpy()对于这种情况来说是简单和简洁的,并且副作用也更快,因为它允许一次复制多个字符并且不检查每个字符是否为空终止符。

HRESULT someFunction( char* buffer, size_t length )
{
    const char* toCopy = ...
    size_t actualLength = strlen( toCopy );
    if( actualLength > length ) {
        return E_UNEXPECTED; // doesn't fit, can't do anything reasonable 
    }
    memcpy( buffer, toCopy, min( length, actualLength + 1 ) );
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)

所以解决方案就是忘记 andstrncpy()strncpy_s()使用memcpy()它来代替。