Как добиться функциональности strncpy () с помощью функции strncpy_s ()? - PullRequest
7 голосов
/ 18 февраля 2011

В некоторых случаях мне действительно нужно strncpy() funcitonalty - например, у меня есть функция в предопределенном интерфейсе, которой передается адрес буфера и размер буфера:

HRESULT someFunction( char* buffer, size_t length );

и задокументировано, что я могу скопировать туда строку с нулевым символом в конце длиной не более 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;
}

Теперь у меня есть этот код инеобходимо перенести его из Visual C ++ 7 в Visual C ++ 9. Я скомпилирую его и вижу предупреждение о том, что strncpy() небезопасно , и вместо этого я должен использовать strncpy_s () .

strncpy_s() предназначен для всегда нулевого завершения буфера, поэтому я не могу использовать его в качестве прямой замены в приведенном выше сценарии.Мне придется возвращать E_UNEXPECTED в строках длиннее length - 1 (не length, как ранее), иначе он просто запустит обработчик ошибок недопустимых параметров, когда строка будет length или длиннее, или программа столкнется снеопределенное поведение.

Решение, которое я применял до сих пор, состоит в том, чтобы просто определить _CRT_SECURE_NO_WARNINGS и заставить компилятор отключиться.

есть ли способ использовать strncpy_s() в качестве фактической заменыstrncpy()

Ответы [ 4 ]

4 голосов
/ 18 февраля 2011

Проблема, с которой вы здесь сталкиваетесь, заключается в том, что ваша функция сама по себе небезопасна, как и 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 ) 

Таким образом вы отключите эти предупреждения только для тех ситуаций, когдавам абсолютно необходимо использовать небезопасные функции.

3 голосов
/ 18 февраля 2011

Вместо этого вы можете использовать memcpy_s .

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;
}
2 голосов
/ 01 августа 2013

Попытка использовать функции str*cpy*() для сценариев с фиксированным целевым буфером является распространенным заблуждением. Дело здесь в том, что эти функции «копируют до появления нулевого символа или другого условия». В этом сценарии есть следующий код:

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

и поэтому код знает фактическую длину строки перед тем, как перейти к копированию. И как только длина известна, имеет смысл использовать 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;
}

Таким образом, решение состоит в том, чтобы просто забыть и strncpy() и strncpy_s() и использовать вместо него memcpy().

1 голос
/ 18 февраля 2011

Вы хотите нулевое завершение, где actualLength < length, и нет нулевого завершения, где actualLength == length, верно?

Так что используйте strncpy_s для случая, где actualLength < length и memcpy_s, где actualLength == length.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...