Вернуться к основам - идиоматический способ скопировать строку в статический массив - PullRequest
1 голос
/ 06 декабря 2010

Хорошо, strncpy не предназначен для работы со строкой с завершением NULL - он не предназначен для строк с завершением NULL (если dest слишком короткий, он не будет завершен NULL, а если dest длиннее, он будет дополнен нулями).

Итак, вот тривиальный код:

const char *src = ....; // NULL terminated string of unknown length
char dest[30];

Как src до dest ?strcpy небезопасен, strncpy тоже плохой выбор.Итак, я ушел с strlen , а затем memcpy?Я полагаю, что решение будет немного отличаться всякий раз, когда я забочусь, dest не будет усечено ( dest меньше, чем длина src ) или нет.

Некоторые ограничения:

  • Устаревший код, поэтому я не хочу и не могу изменить его на std :: string
  • У меня нет strlcpy - GCC не предоставляет его.
  • Код может использоваться в тех частях приложения, где производительность критична (например, я не хочу тратить время на CPU с нулями dest , как strncpy).Тем не менее, я не говорю о преждевременной оптимизации, а скорее о идиотском способе выполнения копирования строк C-way.

Edit

Упс, яозначало strncpy, а не snprintf.Моя ошибка

Ответы [ 7 ]

4 голосов
/ 06 декабря 2010

Я думаю, вы говорите о strncpy(), который может не завершить строку и заполнить остаток буфера нулями.

snprintf() всегда завершает строку назначения (если размер буфера не менее 1) и не дополняет остаток буфера нулями.

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

(и если вы хотите strlcpy(), но у вас его нет, вы можете получить довольно простой источник здесь . Для полноты strlcat() здесь )

4 голосов
/ 06 декабря 2010

С strncpy :

strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';

Это пэды с нулями, но форматирование намного меньше, чем snprintf.Если вам действительно нужно, чтобы компьютер делал как можно меньше, опишите его самостоятельно:

char* last = dest + sizeof(dest) - 1;
char* curr = dest; /* assuming we must not alter 'dest' */
while (curr != last && *src) { *curr++ = *src++; }
*last = '\0'; /* avoids a branch, but always writes.
If branch prediction is working well and the text normally fits:
if (curr == last) { *curr = '\0'; } */
3 голосов
/ 06 декабря 2010

Если вас не волнует усечение, вы можете использовать strncat():

dest[0] = 0;
strncat(dest, src, sizeof dest - 1);
1 голос
/ 06 декабря 2010

Используйте snprintf.Он всегда заканчивается нулем и не выполняет заполнение нулями.Не знаю, откуда у вас неправильные представления об этом ...

1 голос
/ 06 декабря 2010

Я бы просто бросил свой собственный:

for (int i = 0; i < (sizeof(dest) - 1) && src[i] != NULL; i++)
{
    dest[i] = src[i];
}
dest[i] = NULL;

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

0 голосов
/ 06 декабря 2010

Я не уверен, что полностью понимаю ваш вопрос, но если вас беспокоит заполнение нулями, это часто можно сделать довольно эффективно, если вы инициализируете свой массив следующим образом.

char dest[30] = { 0 };

Если вы инициализируете его так, вам не нужно заботиться о дополнительной логике, чтобы добавить '\ 0' в конец строки, и это может даже оказаться быстрее.

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

0 голосов
/ 06 декабря 2010

std::copy(src, src+strlen(src)+1, dest)

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