Когда использовать strncpy или memmove?

(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);

Большое спасибо,

17
задан jbatista 13 November 2011 в 12:58
поделиться

6 ответов

strncpy() используется для копирования данных из источника в dest заданного размера, копируя (padding) 0x00s, если 0x00 байт найден в исходном массиве (строке) до конца буфера. В отличие от strcpy, которая будет блаженно копировать вечно, пока не будет найден 0 байт - даже если этот байт находится далеко за пределами вашего буфера.

memcpy() используется для копирования из источника в dest независимо от того, что содержат исходные данные. Она также имеет тенденцию быть очень аппаратно оптимизированной и часто читает системные слова (ints/longs) за раз, чтобы ускорить копирование, если позволяет выравнивание.

memmove() используется для копирования из перекрывающихся областей источника и назначения (скажем, перемещение содержимого массива внутри себя или что-то подобное - отсюда мнемоника move). Он использует стратегии (например, возможно копирование данных, начиная с задней, а не с передней части) для защиты от проблем, вызванных перекрывающимися областями. Он также может быть немного менее эффективным, так как обычно аппаратная помощь при копировании данных сзади наперед невелика.

bcopy() и ее родственники (bzero и некоторые другие) - это функция копирования байтов, которую я время от времени встречал во встроенных системах. Обычно она копирует данные по одному байту от источника к получателю, чтобы предотвратить проблемы смещения адресов памяти, хотя любой хороший memcpy справится с этим, поэтому ее использование часто вызывает подозрения.

Удачи!

22
ответ дан 30 November 2019 в 10:39
поделиться

Никогда не используйте strncpy (если только вы не имеете дело с той редкой конкретной ситуацией, для которой он был введен). Функция не предназначена для использования с C-строками с завершающим нулем. Название, данное этой функции, является просто исторической ошибкой и является основным источником путаницы для людей, которые пытаются ее использовать. strncpy - это функция, введенная для поддержки так называемых строк «фиксированной ширины», а не строк с завершающим нулем. Использование strncpy со строками с нулевым завершением - плохая практика программирования, даже если для этой цели вы можете придать ей некое подобие «работы».

Функция для «безопасного» копирования строк ограниченной длины не существует в библиотеке C, однако некоторые реализации предоставляют ее под именем strlcpy , которое уже стало де-факто стандартным именем для этой функции. Если ваша реализация не предоставляет strlcpy , реализуйте ее самостоятельно.

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

12
ответ дан 30 November 2019 в 10:39
поделиться

strcpy (и другие методы str*) останавливаются при встрече с байтом NULL (0). memcpy и связанные с ней функции НЕ останавливаются при встрече с байтом NULL.

Если у вас есть двоичные данные, вы должны использовать memcpy. В вашем примере вы копируете двоичные данные, а не строковые.

strncpy - это особый случай, когда копирование прекращается при встрече с байтом NULL, но продолжает заполнять вывод NULL'ами до указанной длины.

6
ответ дан 30 November 2019 в 10:39
поделиться

Если вам не нужно поведение strncpy по заполнению буфера, но нужна безопасность от переполнения буфера, рассмотрите strlcpy

Из wikipedia:

strlcpy предлагает две функции, которые призваны помочь разработчикам программного обеспечения избежать проблем. Функция принимает размер места назначения в качестве параметра, что позволяет избежать переполнения буфера, если параметр размера правильный. Если этот размер больше нуля, то в место назначения всегда записывается нулевой байт, поэтому результирующая строка всегда имеет нулевое окончание (даже если исходная строка была усечена для соответствия).

5
ответ дан 30 November 2019 в 10:39
поделиться

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

Если вы знаете длину строк, memmove() будет разумным выбором - и номинально быстрее, чем strncpy(), потому что ему не нужно проверять нули по ходу дела; он просто копирует соответствующее количество байт. (Я делаю вид, что memcpy() не существует, поскольку она может не сработать, если исходная и целевая области памяти перекрываются, тогда как memmove() сделает все правильно независимо от этого.)

Считайте bcopy() архаичным вариантом функций mem*().

4
ответ дан 30 November 2019 в 10:39
поделиться

Если вы ищете безопасный / быстрый способ копирования, мне понравился следующий метод:

memcpy( dest, src, sizeof (dest));
dest[sizeof(dest) - 1] = '\0';       // ensure null termination

Менее эффективен, но также работает для ограничения количества записываемых байтов и нулевых значений -terminate строку:

sprintf( dest, sizeof (dest), "%s", src);

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

2
ответ дан 30 November 2019 в 10:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: