Почему делает strncpy, не пустой оконечный?

Можно обойти это при помощи класса черт:
Это требует, чтобы Вы настроили specialsed класс черт для каждого фактического класса, который Вы используете.

template<typename SubClass>
class SubClass_traits
{};

template<typename Subclass>
class A {
    public:
        void action(typename SubClass_traits<Subclass>::mytype var)
        {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};


// Definitions for B
class B;   // Forward declare

template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
    public:
        typedef int mytype;
};

// Define B
class B : public A<B>
{
    // Define mytype in terms of the traits type.
    typedef SubClass_traits<B>::mytype  mytype;
    public:

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv)
{
    B myInstance;
    return 0;
} 
71
задан Mateen Ulhaq 12 September 2011 в 23:43
поделиться

11 ответов

Используете ли вы Xcode 3.1 на Snow Leopard? У меня та же проблема:

CGContextRef ctx = ...;
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
UIImage * newImage = [[UIImage imageWithCGImage:cgImage] retain];

CGImageRelease(cgImage); // this should be OK, but it now crashes in Simulator on SL

Я предполагаю, что обновление до Xcode 3.2 устранит проблему.

)) / что бы то ни было, реализация strncat может быть оптимизирована для целевой платформы / платформы в библиотеке.

Конечно, вам нужно проверить, что dst содержит хотя бы nullchar, поэтому правильное использование strncat будет примерно таким:

if(LEN) { *dst = '\0'; strncat(dst, src, LEN-1); }

Я также признаю, что strncpy не очень полезен для копирования подстроки в другую строку, если src короче n символов, строка назначения будет обрезана.

41
ответ дан 24 November 2019 в 13:03
поделиться

Уже существуют реализации с открытым исходным кодом, такие как strlcpy , которые делают безопасное копирование.

http://en.wikipedia.org/wiki/Strlcpy

В ссылки есть ссылки на источники.

24
ответ дан 24 November 2019 в 13:03
поделиться

Первоначально в файловой системе UNIX 7-го издания (см. DIR (5)) были записи каталога, которые ограничивали имена файлов 14 байтами; каждая запись в каталоге состояла из 2 байтов для номера inode плюс 14 байтов для имени, дополненных нулями до 14 символов, но не обязательно с завершающим нулем. Я считаю, что strncpy () был разработан для работы с этими структурами каталогов - или, по крайней мере, он отлично работает для этой структуры.

Учтите:

  • 14-символьное имя файла не было пустым завершено.
  • Если имя было короче 14 байтов, оно дополнялось нулем до полной длины (14 байтов).

Именно этого можно было бы достичь с помощью:

strncpy(inode->d_name, filename, 14);

Итак, strncpy () идеально подходил для своей первоначальной ниши. Это было лишь случайным совпадением относительно предотвращения переполнения строк с завершающим нулем.

(Обратите внимание, что заполнение нулями до длины 14 не является серьезными накладными расходами - если длина буфера составляет 4 КБ и все, что вам нужно, это безопасно скопировать 20 символов в него, то лишние 4075 нулей - серьезный перебор,

24
ответ дан 24 November 2019 в 13:03
поделиться

Некоторые новые альтернативы указаны в ISO / IEC TR 24731 (см. https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317- BSI.html для информации). Большинство этих функций принимают дополнительный параметр, определяющий максимальную длину целевой переменной, гарантирующий, что все строки заканчиваются нулем и имеют имена, заканчивающиеся на _s (для «безопасности»?), Чтобы различать их. из их более ранних «небезопасных» версий. 1

К сожалению, они все еще получают поддержку и могут быть недоступны с вашим конкретным набором инструментов. Более поздние версии Visual Studio будут выдавать предупреждения, если вы используете старые небезопасные функции.

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

errCode_t strncpy_safe(char *sDst, size_t lenDst,
                       const char *sSrc, size_t count)
{
    // No NULLs allowed.
    if (sDst == NULL  ||  sSrc == NULL)
        return ERR_INVALID_ARGUMENT;

   // Validate buffer space.
   if (count >= lenDst)
        return ERR_BUFFER_OVERFLOW;

   // Copy and always null-terminate
   memcpy(sDst, sSrc, count);
   *(sDst + count) = '\0';

   return OK;
}

Вы можете изменить функцию в соответствии со своими потребностями, например, чтобы всегда копировать как можно большую часть строки без переполнения. Фактически, реализация VC ++ может сделать это, если вы передадите _TRUNCATE в качестве счетчика .




1 Конечно, вы все равно должны точно определять размер целевой буфер: если вы предоставляете 3-символьный буфер, но сообщаете strcpy_s(), что в нем есть место для 25 символов, у вас все равно проблемы.
8
ответ дан 24 November 2019 в 13:03
поделиться

Strncpy более безопасен против атак переполнения стека со стороны пользователя вашей программы, он не защищает вас от ошибок вы программист, например как печать строки без завершающего нуля, как вы описали.

Вы можете избежать сбоя из-за проблемы, которую вы описали, ограничив количество символов, выводимых printf:

char my_string[10];
//other code here
printf("%.9s",my_string); //limit the number of chars to be printed to 9
8
ответ дан 24 November 2019 в 13:03
поделиться

Используйте strlcpy () , указанный здесь: http://www.courtesan.com/todd/papers/strlcpy.html

Если ваш libc не имеет реализации, тогда попробуйте эту:

size_t strlcpy(char* dst, const char* src, size_t bufsize)
{
  size_t srclen =strlen(src);
  size_t result =srclen; /* Result is always the length of the src string */
  if(bufsize>0)
  {
    if(srclen>=bufsize)
       srclen=bufsize-1;
    if(srclen>0)
       memcpy(dst,src,srclen);
    dst[srclen]='\0';
  }
  return result;
}

(Написано мной в 2004 году - посвящено общественному достоянию)

5
ответ дан 24 November 2019 в 13:03
поделиться

strncpy работает напрямую с доступными строковыми буферами, если вы работаете напрямую со своей памятью, вы ДОЛЖНЫ теперь размеры буфера, и вы можете установить '\ 0' вручную.

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

3
ответ дан 24 November 2019 в 13:03
поделиться

Я всегда предпочитал:

 memset(dest, 0, LEN);
 strncpy(dest, src, LEN - 1);

исправить это позже, но на самом деле это всего лишь вопрос предпочтений.

3
ответ дан 24 November 2019 в 13:03
поделиться

Не полагаясь на новые расширения, я делал что-то подобное в прошлом:

/* copy N "visible" chars, adding a null in the position just beyond them */
#define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = '\0')

и, возможно, даже:

/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */
#define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)

Почему макросы вместо более новых «встроенных» (?) функции? Потому что раньше было довольно много разных юниксов, а также других сред, отличных от unix (не Windows), которые мне приходилось переносить обратно, когда я ежедневно делал C.

2
ответ дан 24 November 2019 в 13:03
поделиться

Эти функции эволюционировали больше, чем разрабатывались, поэтому на самом деле нет никакого «почему». Вам просто нужно научиться «как». К сожалению, справочные страницы Linux по крайней мере лишены распространенных примеров использования этих функций, и я заметил много злоупотреблений в коде, который я рассмотрел. Я сделал несколько заметок здесь: http://www.pixelbeat.org/programming/gcc/string_buffers.html

2
ответ дан 24 November 2019 в 13:03
поделиться

Вместо strncpy () вы можете использовать

snprintf(buffer, BUFFER_SIZE, "%s", src);

Вот однострочник, который копирует не более size-1 ненулевых символов от src до dest и добавляет нулевой терминатор:

static inline void cpystr(char *dest, const char *src, size_t size)
{ if(size) while((*dest++ = --size ? *src++ : 0)); }
3
ответ дан 24 November 2019 в 13:03
поделиться
Другие вопросы по тегам:

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