Россия, Москва |
Введение в программирование скриптов на C
Файлы
В С принята поточная модель файла данных. Она предполагает, что файл рассматривается как поток байтов. Операции чтения и записи файла опираются на понятия начала потока (первый байт), конца потока (последний байт) и текущей позиции в потоке (последний считанный/записанный байт).
При открытии файла на чтение или запись с ним связывается дескриптор потока данных. Он указывает на структуру данных, в которой хранится необходимая для работы с файлом информация. Место под эту структуру отводится динамически, т.е. в момент исполнения программы. Для того, чтобы избежать "утечки" памяти, файлы после их использования следует закрывать.
Для начала работы файл нужно открыть:
FILE *IN; ... IN = open("text.txt","r");
Объявление (декларация) FILE *IN; определяет переменную IN как указатель на структуру дескриптора файла. Функция open() присваивает указателю IN значение адреса дескриптора файла с именем text.txt. При этом файл открыт только для посимвольного чтения. Если нужно открыть файл для записи, то вместо r следует указать w. Если требуется и чтение, и запись в файл, то его открывают со значением второго аргумента (вместо r ) равным r+.
После работы с файлом его нужно закрыть:
FILE *IN; ... IN = open("text.txt","r"); ... close(IN);
Закрывается файл функцией close(). При этом происходит освобождение памяти из-под структуры дескриптора файла и буферов ввода/вывода, которые были созданы при открытии файла. Желательно закрывать файлы в обратной последовательности (последним закрывается файл, который был открыт первым). Это позволяет избежать фрагментации памяти.
Для чтения данных из файла можно использовать функцию fread():
FILE *IN; char query[1024]; ... IN = open("text.txt","r"); fread(query,1024,1,IN); ... close(IN);
В данном случае в массив символов query считывается один блок данных размером 1024 символа из файла, связанного с дескриптором IN. Если числа 1024 и 1 поменять местами, то функция fread считает 1024 блока по одному символу.
Для записи в файл применяется другая функция — fwrite():
FILE *OUT; ... OUT = open("text.txt","w"); fwrite(query,1024,1,OUT); ... close(OUT);
Значения параметров в этой функции те же, что и в функции fread().
Функции fread() и fwrite() — это функции неформатного ввода/вывода. В них не происходит никакого преобразования данных. Данные записываются в файлы в том виде, в котором они хранятся в переменных. Следует отметить, что в С различают два типа потоков данных: символьные и двоичные. Если fread()/fwrite() применять для двоичного потока, то, действительно, никаких преобразований происходить не будет. Если применять эти функции к символьным потокам данных, то преобразования производятся. Например, выполняется обработка конца строки.
Кроме неформатного ввода/вывода, в С применяют форматный ввод/вывод. Он реализуется через функции fscanf() и fprintf(). Первая функция служит для считывания и преобразования данных, а вторая — для преобразования и записи. Примером применения этих функций может служить счетчик посещения страницы:
#include <stdlib.h> #include <stdio.h> void main() { FILE *IN; int n; IN = open("text.txt","r"); fscanf(IN,"%d",&n); close(IN); IN = open("text.txt","w"); n++; printf("%d",n); fprintf(IN,"%d",n); close(IN); }
В данном случае целое число, записанное ASCII-символами, считывается из файла text.txt, преобразуется в формат целого числа и помещается в переменную n. После этого оно увеличивается на единицу, записывается на старое место и распечатывается в поток стандартного вывода. Если в HTML-странице разместить подстановку (server side include) результатов исполнения этого скрипта, то мы реализуем счетчик посещения страниц.
Препроцессор
Директивы препроцессора позволяют собрать программу на языке С из готовых блоков кода. Кроме того, можно реализовать управление процессом компиляции, например, разработать процедуру условной компиляции для разных операционных систем.
В рамках разработки простых CGI-скриптов нам нужна будет только инструкция включения " include ". Во всех примерах данного раздела она используется для включения в код программы описаний функций из набора стандартных библиотек.
Если необходимо задействовать функции форматного ввода/вывода, а их мы применяем для печати в стандартный вывод, то следует использовать инструкцию #include <stdio.h>:
#include <stdio.h> void main() { printf("Content-type: text/html\n\n"); printf("<HTML>"); printf("<HEAD>"); printf("</HEAD>"); printf("<BODY>"); printf("<H1>Привет от-CGI</H1>"); printf("</BODY>"); printf("</HTML>"); }
Инструкция препроцессора начинается с символа "#". При использовании инструкций включения различают локальные файлы и стандартные файлы включения. Когда применяются стандартные файлы включения, имя файла заключают в "<имя_файла>". При использовании локального файла имя файла заключают в обычные двойные кавычки — "имя_файла". В наших примерах применяются только стандартные файлы включений.
Мы используем файлы включения только для ввода в код программы описаний стандартных функций и констант, с этими функциями связанных. Для наиболее распространенных функций существует файл /usr/include/stdlib.h. Его включения в программу достаточно для того, например, чтобы использовать функции ввода/вывода и сравнения строк:
#include <stdlib.h> void main() { printf("Content-type: text/plain\n\n"); if(strcmp("GET",getenv("REQUEST_METHOD")) { printf("Нет даты в потоке STDIN"); } }
В данном случае в stdlib.h определены шаблоны для функций strcmp() и getenv().
При программировании в среде Unix программист всегда может применить команду man, которая позволяет получить подсказку по использованию той или иной функции C.
Компиляция
Программа на С — это текстовый файл, из которого программа-компилятор создает исполняемый файл. CGI-скрипт — это исполняемый файл. Для компиляции используется компилятор с языка С. В большинстве Unix-платформ этот компилятор носит название cc.
Предположим, что нужно создать программу с именем hello.cgi. Код на С расположен в файле hello.c. В этом случае достаточно выполнить:
bash%cc -o hello.cgi hello.c
Опция " -о " в этой записи определяет имя исполняемого файла. Он задается сразу вслед за ней. Имя файла исходного текста С указывается просто в качестве параметра.
Если в скрипте использовать функции из внешней библиотеки, то компилятору необходимо указать ее адрес:
bash%cc -o test.cgi test.c -lpq
В данном случае мы используем внешнюю библиотеку pq. Опция -l определяет имя библиотеки. Сама процедура сборки программы называется linking (связывание). Отсюда и буква " l " перед именем библиотеки.