Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / C / C++ / Введение в язык C++ / Функции и Файлы /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Заголовочные Файлы - Программирование от RIN.RU
Заголовочные Файлы



Один Заголовочный Файл


Проще всего решить проблему разбиения программы на несколько файлов поместив функции и определения данных в подходящее число исходных файлов и описав типы, необходимые для их взаимодействия, в одном заголовочном файле, который включается во все остальные файлы. Для программы калькулятора можно использовать четыре .c файла: lex.c, syn.c, table.c и main.c, и заголовочный файл dc.h, содержащий описания всех имен, которые используются более чем в одном .c файле:


// dc.h: общие описания для калькулятора




enum token_value {
NAME, NUMBER, END,
PLUS="+", MINUS="-", MUL="*", DIV="/",
PRINT=";", ASSIGN="=", LP="(", RP=")"
};




extern int no_of_errors;
extern double error(char* s);
extern token_value get_token();
extern token_value curr_tok;
extern double number_value;
extern char name_string[256];




extern double expr();
extern double term();
extern double prim();




struct name {
char* string;
name* next;
double value;
};




extern name* look(char* p, int ins = 0);
inline name* insert(char* s) { return look(s,1); }


Если опустить фактический код, то lex.c будет выглядеть примерно так:


// lex.c: ввод и лексический анализ




#include "dc.h"
#include




token_value curr_tok;
double number_value;
char name_string[256];




token_value get_token() { /* ... */ }


Заметьте, что такое использование заголовочных файлов гарантирует, что каждое описание в заголовочном файле объекта, определенного пользователем, будет в какой-то момент включено в файл, где он определяется. Например, при компиляции lex.c компилятору будет передано:


extern token_value get_token();
// ...
token_value get_token() { /* ... */ }


Это обеспечивает то, что компилятор обнаружит любую несогласованность в типах, указанных для имени. Например, если бы get_token() была описана как возвращающая token_value, но при этом определена как возвращающая int, компиляция lex.c не прошла бы из- за ошибки несоответствия типов.


Файл syn.c будет выглядеть примерно так:


// syn.c: синтаксический анализ и вычисление


#include "dc.h"


double prim() { /* ... */ }
double term() { /* ... */ }
double expr() { /* ... */ }


Файл table.c будет выглядеть примерно так:


// table.c: таблица имен и просмотр


#include "dc.h"


extern char* strcmp(const char*, const char*);
extern char* strcpy(char*, const char*);
extern int strlen(const char*);


const TBLSZ = 23;
name* table[TBLSZ];


name* look(char* p; int ins) { /* ... */ }




Заметьте, что table.c сам описывает стандартные функции для работы со строками, поэтому никакой проверки согласованности этих описаний нет. Почти всегда лучше включать заголовочный файл, чем описывать имя в .c файле как extern. При этом может включаться "слишком много", но это обычно не оказывает серьезного влияния на время, необходимое для компиляции, и как правило экономит время программиста. В качестве примера этого, обратите внимание на то, как strlen() заново описывается в main() (ниже). Это лишние нажатия клавиш и возможный источник неприятностей, поскольку компилятор не может проверить согласованность этих двух определений. На самом деле, этой сложности можно было бы избежать, будь все описания extern помещены в dc.h, как и предлагалось сделать. Эта "небрежность" сохранена в программе, поскольку это очень типично для C программ, очень соблазнительно для программиста, и чаще приводит, чем не приводит, к ошибкам, которые трудно обнаружить, и к программам, с которыми тяжело работать. Вас предупредили!


И main.c, наконец, выглядит так:


// main.c: инициализация, главный цикл и обработка ошибок


#include "dc.h"


int no_of_errors;


double error(char* s) { /* ... */ }


extern int strlen(const char*);


main(int argc, char* argv[]) { /* ... */ }


Важный случай, когда размер заголовочных файлов становится серьезной помехой. Набор заголовочных файлов и библиотеку можно использовать для расширения языка множеством обще- и специально- прикладных типов (см. Главы 5, 6, 7, 8). В таких случаях не принято осуществлять чтение тысяч строк заголовочных файлов в начале каждой компиляции. Содержание этих файлов обычно "заморожено" и изменяется очень нечасто. Наиболее полезным может оказаться метод затравки компилятора содержанием этих заголовочных фалов. По сути, создается язык специального назначения со своим собственным компилятором. Никакого стандартного метода создания такого компилятора с затравкой не принято.


<<<  НазадВперед  >>>
 1  2  3  4 


 8  Комментарии к статье  8 8  Обсудить в чате

8  В тему

Компоновка

Файлы как Модули

Как Создать Библиотеку

Функции

Макросы

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь