问题描述:

There're certain cases when I really need strncpy() funcitonalty - for example I have a function in a predefined interface that is passed an address of the buffer and the size of the buffer:

HRESULT someFunction( char* buffer, size_t length );

and it is documented that I can copy a null-terminated string there with length no more than length - if it is exactly of length length I don't null-terminate the string and the caller knows that the string ends at either a null character or at length length whichever happens first and it all works.

Of course I will use strncpy() for that

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;

}

Now I have this code and need to migrate it from Visual C++ 7 to Visual C++ 9. I compile it and see a warning that strncpy() is unsafe and I should instead use strncpy_s().

strncpy_s() is designed to always null-terminate the buffer, so I can't use it as a direct replacement in the above scenario. I'll have to return E_UNEXPECTED on strings longer than length - 1 (not length as previously) or it will just fire an invalid parameters error handler once a string is of length or longer or the program will run into undefined behavior.

The solution I applied so far is to just define a _CRT_SECURE_NO_WARNINGS and make the compiler shut up.

is there any way to use strncpy_s() as an actual replacement to strncpy()?

网友答案:

The problem you're facing here is that your function is unsafe in itself, just like strncpy() is. It is unsafe because callers of your function might forget that the returned strings are not null terminated. If this really is the desired behavior of your function I recommend not to define _CRT_SECURE_NO_WARNINGS and disable the warnings globally but use #pragmas instead:

// 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 ) 

That way you disable those warnings only for those situations where you absolutely have to use unsafe functions.

网友答案:

You might use memcpy_s instead.

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 
    }
    else if ( actualLength < length ) {
        actualLength++; // copy null terminator too
    }
    memcpy_s( buffer, length, toCopy, actualLength );
    return S_OK;
}
网友答案:

Trying to use str*cpy*() functions for scenarios with a fixed destination buffer is a common misconception. The deal here is that those functions "copy until a null character or other condition occurs". In this scenario there's this code in place:

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

and so the code knows the actual string length before it proceeds to copying. And once length is known it only makes sense to use memcpy() which is straightforward and concise for such scenarios and as a side effect also faster since it is allowed to copy more than one character at a time and doesn't check each character for null terminator.

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;
}

So the solution is to just forget both strncpy() and strncpy_s() and use memcpy() instead.

网友答案:

You want null-termination where actualLength < length, and no null-termination where actualLength == length, right?

So use strncpy_s for the case where actualLength < length and memcpy_s where actualLength == length.

相关阅读:
Top