Когда использовать 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);
Большое спасибо,
Ответы
Ответ 1
strncpy()
используется для копирования данных из источника в dest заданного размера, копируя (заполнение) 0x00
если в исходном массиве (строке) до конца буфера найден байт 0x00
. В отличие от strcpy
который будет блаженно копировать до тех пор, пока не будет найден 0
байт - даже если указанный байт находится далеко за пределами вашего буфера.
memcpy()
используется для копирования из источника в dest независимо от того, что содержат исходные данные. Он также имеет тенденцию быть очень аппаратно оптимизированным и часто будет читать системные слова (int
s/long
s) за раз, чтобы ускорить копирование, когда выравнивание позволяет.
memmove()
используется для копирования из перекрывающейся области источника и назначения (скажем, перемещение содержимого массива вокруг себя или чего-то подобного - отсюда и мнемоника перемещения). Он использует стратегии (такие как, возможно, копирование данных, начиная сзади, а не спереди), чтобы защитить от проблем, вызванных перекрытием регионов. Это также может быть немного менее эффективно, так как обычно аппаратная помощь не позволяет копировать данные задом наперед.
bcopy()
и его родственники (bzero
и некоторые другие) - это функция копирования байтов, которую я видел время от времени во встроенных местах. Как правило, он копирует данные по одному байту за раз из источника в место назначения, чтобы предотвратить проблемы со смещением памяти, хотя любой хороший memcpy
справится с этим, поэтому его использование довольно часто подозрительно.
Удачи!
Ответ 2
Вы никогда не должны использовать strncpy
(если вы не имеете дело с той редкой конкретной ситуацией, в которой он был введен). Функция не предназначена для использования с C-строками с нулевым завершением. Название, данное этой функции, является лишь исторической ошибкой и, как представляется, является основным источником путаницы для людей, которые пытаются ее использовать. strncpy
- это функция, введенная для поддержки так называемых строк с фиксированной шириной, а не строк с нулевым завершением. Использование strncpy
с нулевыми строками - это плохая практика программирования, хотя вы можете взломать ее в какое-то сходство с "рабочим" для этой цели.
Функция для "безопасного" копирования строк с ограниченной длиной не существует в библиотеке C, однако некоторые реализации предоставляют ее под именем strlcpy
, который уже стал стандартным именем этой функции для де-факто. Если ваша реализация не предоставляет strlcpy
, выполните ее самостоятельно.
Также верно, что во многих случаях вы можете заменить функцию str...
на функции mem...
, то есть когда вы знаете точное количество копируемых символов.
Ответ 3
strcpy
(и другие методы str *) останавливаются, когда они сталкиваются с байтом NULL (0). memcpy
и связанные функции, чтобы НЕ останавливаться, когда они сталкиваются с байтом NULL.
Если у вас есть двоичные данные, вы должны использовать memcpy. В вашем примере вы копируете двоичные данные, а не строковые данные.
strncpy
- это особый случай, когда он прекратит копирование в NULL-байте, но все равно продолжит заполнять вывод с NULL до указанной длины.
Ответ 4
Если вам не требуется поведение заполнения буфера strncpy
, но вы хотите, чтобы безопасность не переполняла буфер, рассмотрите strlcpy
От wikipedia:
strlcpy
предлагает две функции, которые призваны помочь разработчикам программного обеспечения избежать проблем. Функция принимает размер назначения в качестве параметра, избегая переполнения буфера, если параметр размера правильный. Если этот размер больше нуля, нулевой байт всегда записывается в пункт назначения, поэтому результирующая строка всегда имеет nul-terminated (даже если исходная строка была усечена для соответствия).
Ответ 5
Используйте strncpy()
только в том случае, если вы знаете, что для строки достаточно места - потому что он не гарантирует нулевое завершение, и чрезмерно восторженный, если место назначения намного короче исходной строки (потому что это пустое заполнение строки до полной длины). И если вы знаете длину, вы можете использовать memmove()
...
Если вы знаете длину строк, memmove()
- разумный выбор - и номинально быстрее, чем strncpy()
потому что он не должен проверять наличие нулей в процессе работы; он просто копирует соответствующее количество байтов. (Я притворяюсь, что memcpy()
не существует, так как он может потерпеть неудачу, если исходная и memmove()
области памяти перекрываются, тогда как memmove()
сделает это правильно, независимо от того.)
Думайте о bcopy()
как об архаичном варианте функций mem*()
.
Ответ 6
Если вы ищете безопасный/быстрый способ копирования, я был доволен следующей техникой:
memcpy( dest, src, sizeof (dest));
dest[sizeof(dest) - 1] = '\0'; // ensure null termination
Менее эффективен, но также работает, чтобы ограничить байты, записанные и нуль-завершающие строку:
sprintf( dest, sizeof (dest), "%s", src);
Также возвращает количество байтов, которые оно написало, поэтому вы можете определить, произошло ли усечение.