Чтение онлайн

на главную - закладки

Жанры

Внутреннее устройство Linux
Шрифт:

Объектный файл является двоичным файлом, который процессор уже почти готов понять, если учесть еще несколько моментов. Во-первых, операционная система не знает, как запускать объектные файлы, а во-вторых, вам, вероятно, потребуется скомбинировать несколько объектных файлов и системных библиотек, чтобы создать завершенную программу.

Чтобы создать полностью функционирующий исполняемый файл из одного или нескольких объектных файлов, следует запустить компоновщик, команду ld в Unix. Программисты редко используют эту команду в командной строке, поскольку компилятор C знает, как запускать компоновщик. Для создания исполняемого файла с названием myprog из двух приведенных выше объектных файлов запустите такую команду:

$ cc -o myprog main.o aux.o

Хотя

и возможно скомпилировать несколько исходных файлов вручную, как показано в этом примере, трудно отслеживать их во время компиляции, если число таких файлов велико. Утилита make, описанная в разделе 15.2, является стандартом Unix для управления компиляцией. Эта утилита особенно важна при управлении файлами, описанными в следующих двух разделах.

15.1.2. Заголовочные файлы (Include) и каталоги

Заголовочные файлы C являются дополнительными файлами с исходным кодом, который обычно содержит объявления типов и библиотечных функций. Например, файл stdio.h является заголовочным (см. простую программу в разделе 15.1).

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

Исправление проблем, вызванных включаемыми файлами

Отследить правильный включаемый файл не всегда легко. Иногда несколько включаемых файлов с одинаковыми именами расположены в разных каталогах и неясно, какой из них правильный. Когда компилятор не может обнаружить включаемый файл, сообщение об ошибке выглядит так:

badinclude.c:1:22: fatal error: notfound.h: No such file or directory

Это сообщение говорит о том, что компилятор не может найти заголовочный файл notfound.h, на который ссылается файл badinclude.c. Эта ошибка является прямым следствием такой директивы в первой строке файла badinclude.c:

#include <notfound.h>

По умолчанию в Unix каталогом для включаемых файлов является /usr/include; компилятор всегда просматривает его, если вы явно не укажете ему не выполнять этого. Тем не менее можно настроить компилятор так, чтобы он просматривал другие каталоги (большинство каталогов с заголовочными файлами содержит слово include где-либо в своем имени).

примечание

Из главы 16 вы узнаете о том, как отыскать отсутствующие включаемые файлы.

Предположим, вы обнаружили файл notfound.h в каталоге /usr/junk/include. Можно сделать так, чтобы компилятор видел этот каталог с помощью параме­тра -I:

$ cc -c -I/usr/junk/include badinclude.c

Теперь компилятор не должен спотыкаться на строке кода в файле badinclude.c, которая ссылается на заголовочный файл.

Следует также опасаться включаемых файлов, использующих двойные кавычки (" ") вместо угловых скобок (< >), например так:

#include "myheader.h"

Двойные кавычки означают, что заголовочный файл не располагается в системном каталоге для включаемых файлов и компилятору следует поискать его путь. Часто это говорит о том, что включаемый файл находится в том же каталоге, что и файл с исходным кодом. Если вам встретится проблема с двойными кавычками, то, вероятно, вы пытаетесь скомпилировать неполный исходный код.

Что такое препроцессор C (cpp)?

Оказывается, компилятор C не выполняет работу по отыскиванию всех этих включаемых файлов. Эта задача приходится

на долю препроцессора C — команды, которую компилятор применяет к исходному коду, прежде чем выполнить синтаксический анализ реальной программы. Препроцессор перезаписывает исходный код в такой форме, которую способен понять компилятор; это инструмент, дела­ющий исходный код более легким для чтения (и снабжающий его обходными маневрами).

Команды препроцессора в исходном коде называются директивами, они начинаются с символа #. Существуют три основных типа директив.

Включаемые файлы. Директива #include дает препроцессору указание о том, чтобы он включил весь файл. Обратите внимание на то, что флаг компилятора -I является в действительности параметром, который вынуждает препроцессор искать включаемые файлы в указанном каталоге, как вы видели в предыдущем разделе.

• Макроопределения. Строка, подобная #define BLAH something, говорит препроцессору о том, чтобы он выполнил замену всех вхождений элемента BLAH на элемент something в исходном коде. По соглашению названия макроопределений даются прописными буквами, но не следует удивляться тому, что программисты иногда используют макроопределения, имена которых похожи на функции и переменные. Сплошь и рядом это причиняет массу неприятностей. Многие программисты превращают в спорт неправильное использование препроцессора.

примечание

Вместо того чтобы приводить макроопределения в исходном коде, можно также передавать параметры в компилятор: команда -DBLAH=something будет работать так же, как приведенная выше директива.

• Условные операторы. Можно пометить отдельные фрагменты кода с помощью слов #ifdef, #if и #endif. Директива #ifdef MACRO проверяет, определено ли ма­кроопределение MACRO для препроцессора, а директива #if condition проверяет, является ли результат условия condition ненулевым. Для обеих директив в том случае, когда условие, следующее за директивой if, является ложным, препроцессор не передает компилятору текст программы, который расположен между директивами #if и #endif. Следует привыкнуть к этому, если вы собираетесь исследовать какой-либо код на языке C.

Приведу далее пример условной директивы. Когда препроцессор встречает такой код, он проверяет, есть ли макроопределение DEBUG, и если оно определено, передает компилятору строку, содержащую команду fprintf. В противном случае препроцессор пропускает эту строку и продолжает обработку файла после директивы #endif:

#ifdef DEBUG

fprintf(stderr, "This is a debugging message.\n");

#endif

примечание

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

В Unix препроцессор C называется cpp, но можно также запускать его с помощью команды gcc -E. Однако вам нечасто понадобится запускать препроцессор как таковой.

15.1.3. Связывание с библиотеками

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

Поделиться:
Популярные книги

Мастер...

Чащин Валерий
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Мастер...

Жених из гроба

Сотис Майя
1. Гробокопательница
Фантастика:
юмористическое фэнтези
сказочная фантастика
фэнтези
5.00
рейтинг книги
Жених из гроба

Ищу жену с прицепом

Рам Янка
2. Спасатели
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Ищу жену с прицепом

Гримуар тёмного лорда I

Грехов Тимофей
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Гримуар тёмного лорда I

Заклятие предков

Прозоров Александр Дмитриевич
3. Ведун
Фантастика:
фэнтези
альтернативная история
8.49
рейтинг книги
Заклятие предков

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Рота Его Величества

Дроздов Анатолий Федорович
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Рота Его Величества

Экспансия: Сотрудничество. Том 5

Белов Артем
5. Планетарный десант
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Экспансия: Сотрудничество. Том 5

Отверженный III: Вызов

Опсокополос Алексис
3. Отверженный
Фантастика:
фэнтези
альтернативная история
7.73
рейтинг книги
Отверженный III: Вызов

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Возвышение Меркурия. Книга 8

Кронос Александр
8. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 8

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4