В чем разница между strcpy и stpcpy?

При чтении man-страницы для strcpy я обнаружил, что функция stpcpy также существует. Тем не менее, единственная разница, которую я мог заметить на странице руководства:

 char * stpcpy(char *s1, const char *s2); char * strcpy(char *restrict s1, const char *restrict s2); 

Итак, что здесь restrict ?

restrict сообщает компилятору, что s1 и s2 указывают на разные массивы и что на массивах с заостренными массивами нет перекрытия. В некоторых случаях это может позволить компилятору выполнять дополнительные оптимизации (т. Е. Он может копировать блоки из нескольких символов без необходимости проверки на перекрытие).

Также обратите внимание, что возвращаемое значение отличается: stpcpy возвращает указатель на \0 который был скопирован в буфер назначения, в то время как strcpy возвращает указатель на начало строки (эффективно это return s1; ).

Вопрос, который вы задаете в названии и вопрос об restrict , на самом деле являются двумя разными совершенно не связанными вопросами. Другие ответы уже предоставили вам некоторые хорошие ссылки, которые помогут вам узнать больше об restrict .

Однако основное различие между этими двумя функционалами в действительности не является спецификатором restrict . Фактически, в C99 версии спецификации языка C, strcpy также restrict квалификацию по своим параметрам. То, что вы видите на странице man для strcpy , просто не обновляется, чтобы соответствовать C99.

Основное различие (которое вы, кажется, пропустили) – это возвращаемое значение stpcpy . stpcpy возвращает указатель на завершающий символ \0 целевой строки. Это сразу дает понять цель stpcpy и обоснование ее существования: эта функция предназначена для использования в качестве разумной замены функции strcat в ситуациях, когда вам нужно strcat несколько подстрок в одну строку. Видите ли, strcat работает довольно плохо в таком приложении (я бы даже сказал, что strcat не имеет смысла в реальном коде). Проблема с strcat заключается в том, что она повторно сортирует строку назначения каждый раз, когда вы что-то добавляете к ней, тем самым делая много ненужной работы и в основном генерируя больше тепла, чем свет. Например, следующий код страдает от этой проблемы

 const char *part1, *part2, *part3, *part4; ... char buffer[size]; /* assume that `size` is calculated properly */ strcpy(buffer, part1); strcat(buffer, part2); strcat(buffer, part3); strcat(buffer, part4); 

Этот код можно переопределить гораздо более разумным способом, используя stpcpy

 stpcpy(stpcpy(stpcpy(stpcpy(buffer, part1), part2), part3), part4); 

И если вам не нравятся прикованные вызовы, вы можете использовать промежуточный указатель для хранения возвращаемого значения промежуточных вызовов stpcpy

 char *end = buffer; end = stpcpy(end, part1); end = stpcpy(end, part2); end = stpcpy(end, part3); end = stpcpy(end, part4); 

Конечно, стоит упомянуть, что strcpy и strcat являются стандартными функциями, а stpcpy – нет.

Запись в Wikipedia для restrict

Короче говоря, restrict сообщает компилятору, что сегменты памяти, на которые указывают s1 и s2, не перекрываются; это позволяет коду выполнять меньшую проверку ошибок.

Функция stpcpy() копирует строку, на которую указывает src (включая завершающий символ '\0' ) в массив, на который указывает dest. Строки не должны перекрываться, а длина целевой адреса должна быть достаточно большой, чтобы получить копию.

Это удовлетворяет требованиям для restrict , даже если оно не находится в сигнатуре функции. Если C99 присутствует, его можно добавить.

stpcpy() возвращает указатель на конец строки dest (то есть адрес завершающего нулевого байта), а не на начало.

Это позволяет вам легче конкатенировать многие строки и более эффективно, так как src можно «привязать» к указателю, возвращенному из последнего stpcpy() . Наивная реализация альтернативы, strcat должна найти конец строки dest до того, как она начнет копирование.

Обратите внимание на следующее:

Эта функция не является частью стандартов C или POSIX.1 и не является обычным в Unix-системах, но также не является изобретением GNU. Возможно, это происходит от MS-DOS. В настоящее время он также присутствует в BSD.

Другая разница – это возвращаемое значение. На странице man: «Функции strcpy () и strncpy () возвращают s1. Функция stpcpy () возвращает указатель на завершающий символ` \ 0 ‘s1. ”

strcpy возвращает s1, но stpcpy возвращает s1 + strlen (s2).