файла. Этот буфер должен быть удален в вызывающей подпрограмме
с помощью функции free(). В параметр LENGTH записывается размер
буфера в байтах. В конце временный файл удаляется. */
char* read_temp_file(temp_file_handle temp_file, size_t* length) {
char* buffer;
/* TEMP_FILE -- это дескриптор временного файла. */
int fd = temp_file;
/* переход в начало файла. */
lseek(fd, 0, SEEK_SET);
/* Определение объема данных, содержащихся во временном файле. */
read(fd, length, sizeof(*length));
/* Выделение буфера и чтение данных. */
buffer = (char*)malloc(*length);
read(fd, buffer, *length);
/* Закрытие дескриптора файла, что приведет к уничтожению
временного файла. */
close(fd);
return buffer;
}
Если в программе используются функции потокового ввода-вывода библиотеки языка С и передавать временный файл другой программе не нужно, то для работы с временным файлом больше подойдет функция tmpfile()
. Она создает и открывает временный файл, возвращая файловый указатель на него. Ссылка на файл уже оказывается удаленной, благодаря чему он уничтожается автоматически при закрытии указателя (с помощью функции fclose()
) или при завершении программы.
В Linux есть ряд других функций, предназначенных для генерирования временных файлов или их имен, в частности mktemp()
, tmpnam()
и tempnam()
. Работать с ними нежелательно, поскольку возникают упоминавшиеся выше проблемы, связанные с надежностью и безопасностью.
2.2. Защита от ошибок
Написать программу, которая корректно работает при "разумном" использовании, — трудная задача. Написать программу, которая ведет себя "разумно" при возникновении ошибок, — еще труднее. В этом разделе описываются методики программирования, позволяющие выявлять ошибки на ранних стадиях и решать проблемы, возникающие в ходе выполнения программы.
В представленные ниже фрагменты программ сознательно не включены громоздкие коды проверки ошибок и восстановления после них. так как это привело бы к потере наглядности при рассмотрении основных методик. Тем не менее мы вернемся к данной теме в главе 11, "Демонстрационное Linux-приложение", где будут приведены полностью работающие программы.
2.2.1. Макрос assert()
При написании программы следует помнить о том, что ошибки и непредвиденные ситуации могут радикально менять работу программы на самых ранних стадиях ее выполнения. Нужно стараться выявлять такие ошибки как можно раньше, на этапах разработки и отладки. Остальные ошибки, влияние которых на работу программы незначительно, обычно остаются незамеченными до тех пор, пока пользователи не начнут запускать программу.
Простейший способ выявления ненормальных ситуаций — стандартный макрос assert()
в языке С. Его аргументом является булево выражение. Программа завершается, если выражение оказывается ложным, при этом выводится сообщение об ошибке с указанием исходного файла и номера строки, а также текста выражения, приведшего к ошибке. Макрос assert()
оказывается очень полезным для самых разных проверок целостности, выполняемых внутри программы. Например, с помощью этого макроса проверяют правильность аргументов функций, выполнение входных и выходных условий при вызове функций (а также методов C++) и наличие непредвиденных возвращаемых значений.
Каждый вызов макроса assert()
является не только проверкой, осуществляемой на этапе выполнения, но и документацией, описывающей работу программы непосредственно в ее исходном тексте. Когда программа содержит строку assert (условие), то любой, кто читает исходный текст, будет знать, что в данной точке программы указанное условие всегда должно быть истинным. Если же условие не выполняется, то, очевидно, в программе присутствует ошибка.
В программах, критических к требованиям производительности, проверки assert()
на этапе выполнения могут представлять собой слишком большую нагрузку. В таких случаях программа компилируется с установленной макроконстантой NDEBUG
; для этого в командной строке компилятора указывается флаг -DNDEBUG
. При наличии данной макроконстанты препроцессор убирает из тела программы все вызовы макроса assert()
. И все же помните: делать это имеет смысл только тогда, когда производительность является узким местом программы, причем макрос нужно отключать лишь в наиболее критических файлах.