Какова цель strlcpy и что было в первой версии ее руководства?
Прочитав man strlcpy, я встретил пример:
Since it is known how many characters were copied the first time,
things can be sped up a bit by using a copy instead of an append:
char *dir, *file, pname[MAXPATHLEN];
size_t n;
...
n = strlcpy(pname, dir, sizeof(pname));
if (n >= sizeof(pname))
goto toolong;
if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
goto toolong;
However, one may question the validity of such optimizations,
as they defeat the whole purpose of strlcpy() and strlcat().
As a matter of fact, the first version of this manual page got it wrong.
Чтоwhole purpose of strlcpy
и как именно вышеупомянутый примерdefeats
это?
И что было вthe first version of this manual page
и почему еще важно упомянуть об этом в новом?
2 ответа
Какова цель strlcpy…?
Оба и гарантируют, что не будут предприниматься попытки записи сверх длины, заданной третьим параметром, но они различаются тем, как они обрабатывают последний символ, когда копия выходит за пределы буфера:
- копирует символ из источника в последний байт назначения.
- записывает нулевой символ в последний байт адресата.
strncpy
предположительно имеет такие применения, как полное заполнение целевого буфера, а затем, если источник не был полностью скопирован, использованиеrealloc
чтобы выделить больше памяти для пункта назначения и затем завершить операцию. Однако он может быть подвержен неправильному использованию: поскольку он выдает выходные данные, которые не завершаются нулем, программист, пишущий код с использованием строк, может непреднамеренно рассматривать пункт назначения как строку с нулевым завершением, передавая его вprintf
или другие процедуры, приводящие к сбоям или другим ошибкам.
strlcpy
обеспечивает некоторую защиту от ошибок такого рода, поскольку его выходные данные всегда представляют собой строку с нулевым завершением. (Конечно, могут возникать различные типы ошибок, например, создание неверной строки из-за отсутствия ожидаемой части или из-за того, что она короче, чем ожидалось.)
… а что было в первой версии страницы руководства?
Поскольку на странице руководства указано, что замена этого кода:
if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))
goto toolong;
if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
goto toolong;
с этим кодом:
n = strlcpy(pname, dir, sizeof(pname));
if (n >= sizeof(pname))
goto toolong;
if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
goto toolong;
может повысить эффективность, но существует опасность появления ошибок, мы можем предположить, что в первой версии страницы руководства была ошибка в сравнениях (n >= sizeof(pname)
илиstrlcpy(…) >= sizeof(pname) - n
) или вычисления длины и адреса (pname + n
,sizeof(pname) - n
). Возможно>
использовался вместо>=
илиn-1
на местеn
или какая-то другая ошибка на единицу. Конкретная ошибка несущественна; Дело в том, что более сложный код более подвержен человеческим ошибкам.
Что
the whole purpose of strlcpy
и как именно вышеупомянутый примерdefeats
это?
Этот вопрос не соответствует сути примечания в руководстве, которое предполагает, что в этом случае его следует использовать вместе с (избегая предполагаемой оптимизации), как представлено в предыдущем примере. Приведенный пример не противоречит цели . Это противоречит цели и как пары.
При совместном использовании для этой цели каждому вызову или будет передаваться указатель на общее начало целевого буфера и полный размер буфера. Это избавляет программиста от необходимости отслеживать и использовать информацию о текущей длине строки назначения, которая может быть источником ошибок. Именно предоставление возможности сделать это является тем, что в руководстве называется основной целью этой пары функций, хотя это немного преувеличение.
И что было в
the first version of this manual page
и почему еще важно упомянуть об этом в новом?
Подробности неясны, но общая суть в том, что исходная версия страницы в этом примере содержала ошибку именно такого типа, который соответствует рекомендуемому режиму использования.strlcat()
вместе с предназначен для предотвращения. То есть ошибка в сохранении длины целевой строки или в ее правильном использовании.
Но что касается первого фактически поставленного вопроса, то основная цельstrlcpy()
в качестве отдельной функции необходимо предоставить вариант, гарантирующий NUL-завершение строки назначения. Однако это своего рода отвлекающий маневр, потому чтоstrncpy()
сам по себе один. Непосвященные склонны принять его за более безопасный вариант, но на самом деле он подходит только для определенных, очень особых целей. Это на самом делеstrncat()
это безопаснееstrcpy()
:
#define safer_strcpy(dest, src, size) (*(dest) = '\0', strncat(dest, src, size))