Pull to refresh

Comments 41

«Доктор, откуда у вас такие картинки?»
Самому интересно стало что это такое
https://ru.wikipedia.org/wiki/Trachelophorus_giraffa
Спасибо товарищу Гуголю за нашу спокойную старость (в счастливом детстве поди найди по картинке, что сие).
Видите, у него и родовое название говорящее. :3
Необычные жуки символизируют процесс появления ошибок.
Добавлю: у замечательной функции getaddrinfo свои собственные коды ошибок, и для их перевода в человекочитаемую форму есть отдельная функция gai_strerror. Как-то раз на это налетел, поэтому запомнилось.
Спасибо за setjmp() и longjmp()! Не знал, было очень интересно.
UFO just landed and posted this here
Другой вопрос — так уж ли это надо в C.

Я считаю, что в клиентском коде (обычной юзерской проге) не нужно. Я умеренный противник исключений, ибо они прерывают обычный поток выполнения, что противоречит принципу структурного программирования. Но в системном программировании они могут быть очень полезны. Приведённый Вами пример хорош, пока у вас throw прямо в блоке try, а если оно во вложенном вызове функции и в другом файле — придётся сильнее изловчиться.
UFO just landed and posted this here
Можно ссылку на репу? Интересно глянуть. Вообще проблема, ибо longjmp() не умеет прыгать 'в никуда', ей нужен конкретный буфер с сохранённой средой. Значит, эти буферы в общем случае должны быть глобальными и уникальными. И их нужно генерить неким автоматическим способом (препроцессором?). Я ещё не изучал существующие реализации, мож попробую напишу свою.
UFO just landed and posted this here
Ну и в каждой нити должен быть свой буфер, ибо прыгать между нитями нельзя.
Значит, эти буферы в общем случае должны быть глобальными и уникальными. И их нужно генерить неким автоматическим способом (препроцессором?).

Их можно хранить в стеке вызывающей функции + глобальный указатель на предыдущий буфер.

Точнее, в стеке хранится текущий буфер и указатель на предыдущий буфер, а в в глобальной переменной хранится указатель на текущий буфер.

Наверное стоит добавить что в случае использования sjlj стоит следить за переменными (например маркировать их volatile) потому что longjmp восстанавливает контекст сохраненный в момент вызова setjmp, т.е


    void* data = allocate_some();
    if (!(exc = setjmp(buf))) {
       data = reallocate_some();
        do_work(-3.0f);
    } 
    else {
        // тут значение data МОЖЕТ быть равное значению сохраненному на момент первого вызовы setjmp
        fprintf(stderr, "%s was hadled in %s()\n", exception_name[exc], __func__);
    }  
Есть такое, с этими функциями вообще много проблем, но пример был игрушечным, в реальном коде лучше вообще их не применять.
Вроде как немного затронута тема с C11 и кодом ошибки (например, приведена функция strerror_s).

Стоило уделить больше внимания тому, что в C11 многие функции обзавелись вторым вариантом, который возвращает сразу и значение, и код ошибки (например, fopen и fopen_s). Примеры с функциями из C11 соседствуют с функциями C99 (в дидактических целях стоило давать все примеры с fopen_s).
Приводить все примеры из Annex K бесполезно, ибо он почти нигде не реализован, и где мы взяли код ошибки: из errno, или вернули из функции — не принципильно.
Более того, ходили слухи, что его могут вообще исключить из будущих обновлений ISO C.
Вот, а чёртова Visual Studio тр&%ет мне мозг в warning-ах, что fopen is depracated, use fopen_s.

Хотя strcat_s и strcpy_s очень даже кстати, спасут от многих уязвимостей с переполнением буфера.
Windoпроблемы. ;-) Ни в ISO C11, ни в POSIX они не deprecated ни в коей мере. Более того, не знаю, как в новой версии VC, а ещё недавно порядок параметров в прототипы MS функций не был совместим с Annex K из C11. То есть MS продвинули свои safe функции в ISO C, но парни из комитета взяли и сделали версии функций, не совместимые вообще ни с одной существующей реализацией! В общем, такие дела.
То есть MS продвинули свои safe функции в ISO C, но парни из комитета взяли и сделали версии функций, не совместимые вообще ни с одной существующей реализацией!

Как это они умудрились продвинуть мимо комитета, или как комитет мог перепринять? Помоему microsoft сами себе придумали эти функции и пометили старые как depricated.

особенно MS любит изобретать всякие _wfopen_s, _strncpy_l, _mbsstr, _mbstrlen и т.п.
Я свечу не держал, но вроде бы MS их придумали и предложили комитету, а они их сделали по своему.
Подробнее:
http://stackoverflow.com/questions/372980/do-you-use-the-tr-24731-safe-functions
http://stackoverflow.com/questions/2169016/mac-solution-for-safe-alternatives-to-unsafe-c-c-standard-library-function
https://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx
Я привёл ссылку http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm в эссе. strcat_s() и strcpy_s() как раз не особо полезны, в C99 ввели 'n' функции: strncat() и strncpy(). Существенная разница в том, что 's' функции не используют errno, а возвращают код ошибки. Это было бы хорошо, если б не совместимость и усложение прототипов. Очень сложный вопрос, что лучше.
Ознакомился. Оказывается, strncpy делает лишнюю работу по обнулению всего буфера (а если брать с запасом char fileName[4096]; это лишнее время CPU). А strncat неинтуитивна — size это вовсе не размер destination буфера, и зануление остатка не происходит.

Где-то была статья про разношёрстность стандартной библиотеки PHP, похоже C в ту же сторону идёт.
похоже C в ту же сторону идёт.

с означенных событий прошло более 15 лет, с разношерстностью все более-менее ок.

Всё зависит от использования. Обычно обнуление очень удобно. Если у вас строка записалась не полностью или вообще не записалась, вы всегда можете глянуть, где она закончится. Многие наоборот считают, что новый интерфейс не интуитивен. Я его не использую, ибо в большинстве UNIX он отсутствует.
Если у вас строка записалась не полностью или вообще не записалась, вы всегда можете глянуть, где она закончится
Понятно, что nul character надо писать. Но только один, зачем занулять весь неиспользуемый остаток буфера. Кстати, если строка записалась не полностью (буфер короче строки), nul character не пишется в strncpy и мы получаем некорректную asciiz-строку.
Обнуляется не весь буффер, только если длина строки короче, чем нужно было скопировать символов.
If, after copying the terminating null character from src, count is not reached, additional null characters are written to dest until the total of count characters have been written.

О чём я и писал — «весь неиспользуемый буфер».
char dst[4096];
strncpy(dst, "test", sizeof(dst));

Нужно в dst всего лишь 5 байт записать, а будут записаны все 4096 (4091 записанных байт — оверхед).
char * strncpy ( char * destination, const char * source, size_t num );

Copies the first num characters of source to destination. (http://www.cplusplus.com/reference/cstring/strncpy/)

Вы неправильно используете. Не sizeof(dst), а strlen("test").

Ну или


strncpy(dst, "some long test", 4);

Хотя маны говорят что


One valid (and intended) use of strncpy() is to copy a C string to a fixed-length buffer while ensuring both that the buffer is not overflowed and that unused bytes in the target buffer are zeroed out (perhaps to prevent information leaks if the buffer is to be written to media or transmitted to another process via an interprocess communication technique).

Так что я скорее неправ.

Ну что же вы, честное слово. Спецификации пишут, чтобы их читали. :3

char dst[4096];
strncpy(dst, "test", strlen("test") + 1); \\ место для '\0'

n говорит, сколько символов нужно взять из src. Но вообще, strlcpy() действительно выглядит лучше.
strncpy(dst, "test", strlen("test") + 1); \\ место для '\0'
Плохой пример. В таком виде никакого смысла в strncpy нет, тут она полностью равноценна strcpy
ААА… Тут я начинаю понимать, что strncpy — не замена strcpy_s, как это вы предлагали выше.

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

Например:
struct Header
{
    char name[20];
    char title[30];
} header;
// ...
char localname[21];
strncpy(localname, header.name, sizeof(header.name));
Я ничего подобного не говорил, и не мог. Грубо говоря, strncpy() может копировать строки у которых отсутствует '\0' в конце. (strcpy() понятное дело не может). Похоже, нужно ещё одно эссе про строковые функции.
UFO just landed and posted this here
Sign up to leave a comment.

Articles

Change theme settings