Российский государственный гуманитарный университет
Опубликован: 15.08.2003 | Доступ: платный | Студентов: 20 / 2 | Оценка: 3.91 / 3.79 | Длительность: 06:55:00
Лекция 4:

Введение в программирование скриптов на C

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Аннотация: В этой лекции подробно разбираются особенности программирования CGI-скриптов на языке C. Определяются правила вызова скрипта, передачи ему данных и получение результатов работы скрипта для дальнейшего использования в HTTP-обмене и генерации HTML-страниц. Разбираются причины эффективности C-скриптов по сравнению с другими инструментами.

Информация

Язык программирования C — это традиционный инструмент разработки программного обеспечения, используемый на протяжении последних 25 лет (с момента появления Unix). С учетом того, что Unix в настоящее время является основной серверной средой, умение программировать CGI-скрипты на C является одним из необходимых условий успешной работы Web-инженера.

Вникнув повнимательнее в спецификацию CGI, любой программист поймет, что спецификация создавалась с расчетом на Unix и С. Работа с переменными окружения и потоками стандартного ввода/вывода построена с учетом особенностей среды и средств программирования. При адаптации спецификации CGI в других средах, например, MS-Windows, программирование многих механизмов обмена приходится модифицировать.

Большинство задач при разработке скриптов можно решить средствами Perl, но есть ряд задач, которые требуют использования C-программ. Наиболее распространенным применением C являются скрипты-интерфейсы к базам данных. В качестве примера такого интерфейса воспользуемся библиотекой PostgreSQL.

В данном разделе речь пойдет о программировании CGI-скриптов на классическом C без объектно-ориентрованных особенностей C++.

Общая структура C-скрипта

Скрипт на языке C ничем не отличается от обычной C-программы. Собственно, это набор процедур, среди которых есть главная процедура. Этой главной процедуре передается управление при загрузке программы в оперативную память. Главная процедура контролирует вызов других процедур и весь ход выполнения программы. Простой скрипт — это одна главная процедура.

При разработке С-скрипта следует всегда помнить, что в отличие от скрипта на Bash и Perl, С-скрипт, прежде чем выполнить, нужно еще и откомпилировать, т.е. превратить в исполняемый компьютером код. Если в системе нет компилятора для C, то программировать С-скрипты будет довольно сложно.

Синтаксически главная процедура выглядит следующим образом:

#include <stdlib.h>
#include <stdio.h>
void main(argc,argv,env)
int *argc;
char *argv[];
char *env[];
{
/* тело программы */
}

В этом фрагменте представлены все основные элементы программирования CGI-скриптов на С. Строки в начале программы ( #include... ) позволяют включить в текст программы декларации (описатели) стандартных функций. Строка " void main..." — это объявление главной процедуры. В качестве параметров в данную процедуру (функцию) передаются:

  • число аргументов командной строки — argc ;
  • указатель на массив аргументов командной строки — argv ;
  • указатель на массив переменных окружения — env.

Само тело программы помещается между символами фигурных скобок "{...}". Фраза "тело программы" размещена между парой "/* ... */". Это комментарий. Сама программа на С состоит из операторов. Операторы могут быть простые и составные. Простые операторы – это, например, оператор присваивания. Составной оператор — это блок. Блок представляет собой последовательность операторов, заключенную в фигурные скобки "{...}". В конце простого оператора должен стоять символ ";". В нашем примере объявление (декларирование) переменных перед блоком тела программы — это последовательность простых операторов.

Про С часто говорят, что в языке только пять операторов, а все остальное — это библиотека стандартных функций. Операторов в нем, конечно, больше, но такая характеристика в целом верна.

Стандартный поток вывода

Стандартный поток вывода в С ассоциируется с дескриптором STDOUT. Самым распространенным способом записи данных в этот поток является функция форматного вывода printf. Если скрипт должен что-то передать браузеру пользователя, то первое, что нужно сделать — это применить printf для формирования HTTP-заголовка:

main()
{
printf("Content-type: text/html\n\n");
printf("<H1>C и CGI</H1>");
}

Первый вызов printf формирует заголовок — определяет тип тела HTTP-отклика, а второй вызов формирует заглавие первого уровня в HTML-документе. В общем случае у функции printf три аргумента: printf(FILE,"format",VARS_LIST); FILEдескриптор файла, "format" — формат вывода данных, VARS_LISTсписок переменных, чьи значения подлежат выводу. Если дескриптор файла опущен, то вывод направляется в поток стандартного вывода. Список переменных указывается в том случае, если в формате вывода есть шаблоны вывода для переменных из этого списка.

Для каждого типа данных в С существует свой шаблон вывода. Перечислим только некоторые из них:

%d — вывод целого числа;
%s — вывод массива символов (строки);
%f — вывод вещественного числа;
%x — вывод целого числа в шестнадцатеричном
     виде.

Для того, чтобы распечатать аргументы командной строки, можно применить следующий формат:

int i;
...
for(i=0;i<argc;i++)
{
printf("arg[%d]=%s\n",i,argv[i]);
}

В данном случае переменная цикла i — это целая константа, поэтому в квадратных скобках указано [%d]. Второй аргумент списка переменных — указатель на массив символов (строка, содержащая значение аргумента командной строки ), поэтому после знака равенства ("=") применен шаблон вывода массива символов %s.

Переменные окружения

Третий аргумент главной процедуры — указатель на массив переменных окружения, каждый элемент которого представляет собой строковую константу вида "имя-значение". Неудобство работы с этим массивом заключается в том, что заранее не известно, сколько элементов он содержит. Список переменных окружения кончается в тот момент, когда при его переборе встречается указатель NULL. Пример такого перебора представлен ниже:

#include <stdlib.h>
#include <stdio.h>
void main(argc,argv,env)
int argc;
char *argv[];
char *env[];
{
int i;
i=0;
while(env[i])
{
printf("%d:%s\n",i,env[i]);
i++;
}

}

В данном случае перебор идет до тех пор, пока значение указателя больше 0. При этом переменные окружения выдаются в виде "имя:значение". Для того, чтобы воспользоваться этими значениями, придется разбирать каждую строку, выделяя имя и значение переменной при помощи манипуляций с адресами внутри строки. Любые адресные операции — это потенциальные ошибки (хотя они и позволяют писать быстрые программы).

К счастью, в С есть функция getenv(). В качестве аргумента этой функции достаточно указать имя переменной окружения, и система вернет указатель на его значение. Например, необходимо знать, сколько символов нужно считать со стандартного ввода скрипта:

int i,n;
char *query;
...
n = atoi(getenv("CONTENT_LENGTH"));
query = (char *) malloc(n+1);
for(i=0;i<n;i++)
{
query[i] = getc();
}
...
free(query);

В этом примере при помощи последовательного применения getenv и atoi (ascii to integer) из переменной окружения в переменную целого типа помещается значение переменной окружения — CONTENT_LENGTH. Последовательное применение функций здесь необходимо, т.к. значение переменной окружения — строка, а мы хотим использовать число, следовательно, строку символов следует не только получить, но еще и преобразовать в число.

Для преобразования строк в числа часто используют функцию форматного ввода sscanf. В нашем случае это выглядело примерно следующим образом:

char *length;
int n;
...
length = getenv("CONTENT_LENGTH");
sscanf(length,"%d",&n);
...

Следует заметить, что sscanf — это довольно сложная функция. Она предназначена для ввода любой информации и ее преобразования. Как показывает практика, иногда sscanf работает не так, как предполагает программист. Поэтому незачем стрелять из пушки по воробьям — применяйте лучше специализированные функции преобразования, например, atoi, если это возможно.

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >