(gcc 4.4.4 c89)
Я всегда использовал strncpy
скопировать строки. Я действительно никогда не использовал memmove
или memcpy
очень. Однако я просто задаюсь вопросом, когда был бы Вы решать, использовать ли strncpy
, memmove
, или memcpy
?
Код, который я пишу, для клиент-серверного приложения. В документации они используют bcopy
. Однако я мог сделать то же с другими?
bcopy((char*)server->h_addr,
(char*)&serv_addr.sin_addr.s_addr,
server->h_length);
Большое спасибо,
strncpy()
используется для копирования данных из источника в dest заданного размера, копируя (padding) 0x00
s, если 0x00
байт найден в исходном массиве (строке) до конца буфера. В отличие от strcpy
, которая будет блаженно копировать вечно, пока не будет найден 0
байт - даже если этот байт находится далеко за пределами вашего буфера.
memcpy()
используется для копирования из источника в dest независимо от того, что содержат исходные данные. Она также имеет тенденцию быть очень аппаратно оптимизированной и часто читает системные слова (int
s/long
s) за раз, чтобы ускорить копирование, если позволяет выравнивание.
memmove()
используется для копирования из перекрывающихся областей источника и назначения (скажем, перемещение содержимого массива внутри себя или что-то подобное - отсюда мнемоника move). Он использует стратегии (например, возможно копирование данных, начиная с задней, а не с передней части) для защиты от проблем, вызванных перекрывающимися областями. Он также может быть немного менее эффективным, так как обычно аппаратная помощь при копировании данных сзади наперед невелика.
bcopy()
и ее родственники (bzero
и некоторые другие) - это функция копирования байтов, которую я время от времени встречал во встроенных системах. Обычно она копирует данные по одному байту от источника к получателю, чтобы предотвратить проблемы смещения адресов памяти, хотя любой хороший memcpy
справится с этим, поэтому ее использование часто вызывает подозрения.
Удачи!
Никогда не используйте strncpy
(если только вы не имеете дело с той редкой конкретной ситуацией, для которой он был введен). Функция не предназначена для использования с C-строками с завершающим нулем. Название, данное этой функции, является просто исторической ошибкой и является основным источником путаницы для людей, которые пытаются ее использовать. strncpy
- это функция, введенная для поддержки так называемых строк «фиксированной ширины», а не строк с завершающим нулем. Использование strncpy
со строками с нулевым завершением - плохая практика программирования, даже если для этой цели вы можете придать ей некое подобие «работы».
Функция для «безопасного» копирования строк ограниченной длины не существует в библиотеке C, однако некоторые реализации предоставляют ее под именем strlcpy
, которое уже стало де-факто стандартным именем для этой функции. Если ваша реализация не предоставляет strlcpy
, реализуйте ее самостоятельно.
Также верно, что во многих случаях вы можете заменить функцию str ...
функциями mem ...
, т.е. когда вы знаете точное количество символов для копирования .
strcpy
(и другие методы str*) останавливаются при встрече с байтом NULL (0). memcpy
и связанные с ней функции НЕ останавливаются при встрече с байтом NULL.
Если у вас есть двоичные данные, вы должны использовать memcpy. В вашем примере вы копируете двоичные данные, а не строковые.
strncpy
- это особый случай, когда копирование прекращается при встрече с байтом NULL, но продолжает заполнять вывод NULL'ами до указанной длины.
Если вам не нужно поведение strncpy
по заполнению буфера, но нужна безопасность от переполнения буфера, рассмотрите strlcpy
Из wikipedia:
strlcpy
предлагает две функции, которые призваны помочь разработчикам программного обеспечения избежать проблем. Функция принимает размер места назначения в качестве параметра, что позволяет избежать переполнения буфера, если параметр размера правильный. Если этот размер больше нуля, то в место назначения всегда записывается нулевой байт, поэтому результирующая строка всегда имеет нулевое окончание (даже если исходная строка была усечена для соответствия).
Используйте strncpy()
только если вы знаете, что для строки достаточно места - потому что она не гарантирует нулевое завершение, и будет слишком энтузиастична, если конечная строка намного короче исходной (потому что она заполняет строку нулями до полной длины). И если вы знаете длину, вы можете использовать memmove()
...
Если вы знаете длину строк, memmove()
будет разумным выбором - и номинально быстрее, чем strncpy()
, потому что ему не нужно проверять нули по ходу дела; он просто копирует соответствующее количество байт. (Я делаю вид, что memcpy()
не существует, поскольку она может не сработать, если исходная и целевая области памяти перекрываются, тогда как memmove()
сделает все правильно независимо от этого.)
Считайте bcopy()
архаичным вариантом функций mem*()
.
Если вы ищете безопасный / быстрый способ копирования, мне понравился следующий метод:
memcpy( dest, src, sizeof (dest));
dest[sizeof(dest) - 1] = '\0'; // ensure null termination
Менее эффективен, но также работает для ограничения количества записываемых байтов и нулевых значений -terminate строку:
sprintf( dest, sizeof (dest), "%s", src);
Также возвращает количество байтов, которое она должна была бы записать, чтобы вы могли определить, имело ли место усечение.