Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Красивый и безопасный код в С (http://forum.oszone.net/showthread.php?t=29597)

hasherfrog 06-07-2004 13:01 204849

Стандартная ошибка начинающего (и не только) программиста - переполнение буфера при копировании строк. Вот не совсем корректный код:
Код:

#define SZSIZE 100
char sz[SZSIZE];
strcpy(sz, pszSomeData);

Совсем не вариант, который тем не менее часто используют (100 - как пример):
Код:

char sz[SZSIZE*100];
strcpy(sz, pszSomeData);

Более приемлимый вариант:
Код:

char sz[SZSIZE];
strncpy(sz, pszSomeData, sizeof(sz));

Но тут есть неприятность - последний символ может оказаться не 0. Тогда последующий strlen(sz) может дать сбой. Очевидно, если предусмотреть и эту возможность, надо предохраниться, дописав нулик руками. Но вот какой вариант "красивее"?

Такой:
Код:

char sz[SZSIZE];
strncpy(sz, pszSomeData, sizeof(sz) - 1);
strcat(sz, "\0");

Или такой:
Код:

char sz[SZSIZE + 1];
strncpy(sz, pszSomeData, SZSIZE);
sz[SZSIZE] = '\0';

Или такой:
Код:

char sz[SZSIZE];
strncpy(sz, pszSomeData, sizeof(sz));
sz[SZSIZE - 1] = '\0';

Может, ещё кто какой вариант знает?

Добавлено:

О, забыл.
Код:

char sz[SZSIZE];
memset(sz, 0, sizeof(sz));
strncpy(sz, pszSomeData, sizeof(sz) - 1);

Очевидно, что memset придётся вызывать каждый раз перед копированием.

ivank 06-07-2004 17:55 204850

Извращаться - так красиво.
Код:

int len;
char *sz;

len = strlen(data) + 1;
sz = (char*)alloca(len);

strcpy(sz, data);
/* или */
memcpy(sz, data, len);

P.S. Ненавижу венгерскую нотацию.

DAnG 07-07-2004 07:19 204851

перефразируем :)
Код:

#define strNcpy(dest,src,maxsize) \
   { \
      strncpy(dest, src, maxsize - 1); \
      dest[maxsize-1]=0; \
   }

P.S. на с++ все красивее будет, однако

hasherfrog 07-07-2004 14:37 204852

ivank
Фишка в том, что использование динамической памяти накладывает на программиста обязательство следить за использованными ресурсами. Убирать за собой мусор - тоже своего рода искусство. Но если предположить, что всё будет почищено , то ещё вариант:
Код:

char *psz;
psz = strdup(pszSomeData);
//...
if (psz) free(psz); psz = NULL;


ivank 07-07-2004 20:35 204853

hasherfrog
Так alloca - не динамисечкая память, в этом вся фишка :) Она на стеке память выделяет. Правда, может возникнуть stack overflow.

hasherfrog 08-07-2004 09:51 204854

ivank
Да, я лоханулся, alloca а не alloc. Не заметил во-первых, а во-вторых, я никогда ей не пользуюсь из-за man alloca:
Цитата:

Эта функция не регламентируется стандартами POSIX или SUSv3.
А для меня POSIX - критично.

ivank 08-07-2004 18:49 204855

Ну... Я на самом деле тоже, поскольку пользую C++, а там и  (относительно) умные указатели сделать несложно.

Я, кстати, не знаю ни одной юниксообразной операционка , где этой ф-ии не было бы. В Windows оно тоже есть, только alloca_ зовётся. Так что, имхо, из-за непереносимости её не пользовать довольно таки странно.

P.S. В C99 есть массивы перменного размера. Точнее, не совсем переменного. Поскольку, по сути это та же alloca, но присутствующая в стандарте.

hasherfrog 09-07-2004 09:38 204856

Цитата:

Цитата ivank
из-за непереносимости её не пользовать довольно таки странно.

И всё-таки траблы будут. Не у всех, конечно. У м$ про _alloc сказано: Security Note: In Windows XP, if _alloca is called inside a try/catch block, you must call _resetstkoflw in the catch block.
Но в общем случае, в принципе, в С можно юзать. Жаль, что strdupa в RTL у м$ нет. Это был бы идеальный вариант. :)


hasherfrog 13-07-2004 12:12 204857

Ну вот, сам же и словил багу.
Код:

char sz[SZSIZE];
strncpy(sz, pszSomeData, sizeof(sz) - 1);
strcat(sz, '\0');

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


Время: 02:10.

Время: 02:10.
© OSzone.net 2001-