Как работает strcpy_s?

Как мы все знаем, strcpy_s — это безопасная версия strcpy.

Но интересно, как это работает...

давайте посмотрим несколько примеров.

объявление strpy_s:
errno_t strcpy_s(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)

eg1

char dest[5];
char* src = "abcdefg";
strcpy_s(dest,5,src);

Он вернет утверждение.
Я думаю, что могу понять это, используйте _SIZE, чтобы убедиться, что мы не можем скопировать больше символов, чем _SIZE.

Но.. я не могу понять это:

char dest[5];
char* src = "abcdefg";
strcpy_s(dest,10,src);

мы все еще можем получить утверждение, как это произошло?

пс, ошибка была:

Выражение Debug Assertion Failed
: (L"Буфер слишком мал"&&0)


In VS2013

будет ли strcpy_s проверять размер адресата внутри своего тела?? и если правда то как? как проверить указатель типа _DEST?


person Joey    schedule 26.04.2014    source источник
comment
Внимательно прочитайте документацию: MSDN   -  person Jens    schedule 26.04.2014
comment
Ваш второй пример неверен. Параметр _SIZE должен правильно указывать размер буфера. Если вы укажете 10 для _SIZE, но ваш буфер всего 5, то результат не определен. Strcpy_s никак не может поймать эту ошибку.   -  person Brandin    schedule 26.04.2014
comment
на самом деле было утверждение.   -  person Joey    schedule 27.04.2014


Ответы (4)


На самом деле это то, как получить размер массива стека во время выполнения, не превращая его в указатель:

template<typename T, size_t N> 
size_t arrSize(T (&array)[N])  
{
  return N;
}

Вы отправляете его как ссылку на шаблон, и механизм шаблона определяет размер. Итак, вы можете сделать что-то вроде

int myArray[10];
cout << arrSize(myArray); // will display 10

Так что я предполагаю, что именно так "безопасный" MS strcpy_s проверяет размеры. В противном случае, если вы передадите только указатель, НЕТ СТАНДАРТНО-СООТВЕТСТВУЮЩЕГО способа получения размера.

person vsoftco    schedule 13.05.2014
comment
хорошая точка зрения! Я не так хорошо знаком с C++, думаю, мне нужно немного времени на шаблон в C++ :) спасибо! - person Joey; 12.09.2014
comment
Почему это вообще принятый ответ? Вопрос был о С. - person Tanveer Badar; 01.01.2019

MSDN Говорит: "Функция strcpy_s копирует содержимое в адрес strSource, включая завершающий нулевой символ, в место, указанное параметром strDestination. Целевая строка должна быть достаточно большой, чтобы вместить исходную строку и завершающий нулевой символ. Поведение strcpy_s не определено, если исходная и целевая строки перекрываются».

person Santosh Dhanawade    schedule 26.04.2014
comment
так это было не так безопасно? - person Joey; 26.04.2014
comment
Каково ваше определение сейфа? - person Lee White; 26.04.2014
comment
когда мы пытаемся использовать эту функцию, например, strcpy_s(dest,10,src); мы получим исключение или ничего не будем делать - person Joey; 26.04.2014
comment
Учитывая, что Microsoft создала эту функцию, разве Microsoft не должна определять, что означает безопасный, и объяснять это в документации? Если они хотят, чтобы мы использовали его, то разве они не должны объяснять, почему это безопаснее? - person shawn1874; 11.10.2016
comment
Это безопасно в том смысле, что неопределенное поведение можно предотвратить, избегая переполнения буфера и проблем с нулевыми указателями. В случае перекрытия памяти все еще может иметь место неопределенное поведение. Я не уверен, что Microsoft очень хорошо определила безопасность. Это больше похоже на обеспечение определенного поведения для состояния ошибки. Если strcpy_s используется со слишком маленьким целевым буфером, поведение по умолчанию по-прежнему состоит в том, чтобы прервать программу, но избежать переполнения буфера. - person shawn1874; 11.10.2016

В режиме DEBUG API-интерфейсы MicroSoft заполняют буфер значением 0xfd, поэтому они могут проверить наличие переполнения.

Эта функция не обрезает скопированную строку, а вызывает исключение!

Всегда сложно указать размер целевого буфера (используйте _countof, а не sizeof), в основном, когда вы используете указатель!

У меня больше проблем с этими "_s" API, чем со стандартными!!

person Ananké    schedule 12.04.2016

dest не может содержать более 5 символов, поэтому вы получаете ошибку. Это не из-за _SIZE. Если dest было char*, вам нужно убедиться, что вы выделили для него достаточно памяти, вы не получите никаких ошибок компиляции. Но в вашей программе dest имеет фиксированный размер, а strcpy_s, в отличие от strcpy, проверяет размер целевого буфера (если может, а в данном случае может, так как его размер определяется во время компиляции). Прочитайте это

http://www.cplusplus.com/forum/beginner/118771/

По сути, strcpy_s — это «безопасная» версия strcpy, она не позволяет вам переполняться. Из стандарта: C (2011) и ISO/IEC WDTR 24731 - strcpy_s: вариант strcpy, который проверяет размер целевого буфера перед копированием. Внутренне, вероятно, strcpy_s утверждает sizeof(dest)<SIZE.

person vsoftco    schedule 26.04.2014
comment
как проверить размер буфера назначения? - person Joey; 26.04.2014
comment
с sizeof, я только что отредактировал свой комментарий :) Но это будет работать только для статически определенных массивов, а не для указателей, для которых компилятор не знает, сколько памяти (если есть) вы выделили. - person vsoftco; 26.04.2014
comment
так что мы не можем получить размер dest? - person Joey; 26.04.2014
comment
нет, его можно преобразовать в указатель, однако sizeof(char[5]) равно 5, а не sizeof(char*), который обычно 32-битный (или 64-битный, если у вас 64-битная ОС). Просто сделайте printf("%d ",sizeof(dest));, чтобы убедить себя :) sizeof для любого статически определенного массива вернет размер массива. - person vsoftco; 26.04.2014
comment
спасибо .. я знаю это, но когда мы вызываем функцию, используем char[5] в качестве аргумента, он станет указателем .. поэтому не могу получить его размер, это было правильно? - person Joey; 26.04.2014
comment
Понятно... на самом деле ты прав... Теперь не знаю, как strcpy_s проверяет размер dest внутри своего тела... - person vsoftco; 26.04.2014
comment
Я думаю, что это какое-то внутреннее усовершенствование компилятора, сделанное Microsoft, каким-то образом функции имеют доступ к размерам статических массивов, по крайней мере, в режиме отладки. Если вы скомпилируете в режиме Release, вы, вероятно, не получите никаких ошибок и переполнитесь буфером. Если я не ошибаюсь, я думаю, что в стандартном C нет способа определить размер массива, переданного функции внутри функции. Я не могу придумать никакого другого объяснения. - person vsoftco; 26.04.2014
comment
ах .. в режиме выпуска .. все то же самое - person Joey; 26.04.2014
comment
@ Джоуи, ты не должен иметь размер dest; вы должны передать его вместе с dest или, что еще лучше, использовать вместо него std::string. - person AnotherParker; 24.07.2014