Подтвердить что ты не робот

В чем разница - 1) Препроцессор, компоновщик, 2) Файл заголовка, библиотека? Правильно ли я понимаю?

Хорошо, до сегодняшнего утра я был совершенно смущен между этими условиями. Надеюсь, у меня есть разница, надеюсь.

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

После небольшого поиска в googling и (это термин?: p), я понял, что заголовочный файл в основном содержит декларации функций, тогда как фактическая реализация находится в другом двоичном файле, называемом библиотекой (я все еще не на 100% уверены в этом).

Итак, предположим, что в следующей программе: -

#include<stdio.h>
int main()
{
      printf("whatever");
      return 0;
}

Препроцессор включает в себя содержимое файла заголовка в коде. Компилятор/компилятор + ассемблер выполняет свою работу, а затем, наконец, компоновщик объединяет этот объектный файл с другим объектным файлом, который фактически сохранил способ printf().

Правильно ли я в своем понимании? Я могу быть в отъезде... так что, пожалуйста, помогите мне?

Изменить: Я всегда задавался вопросом о С++ STL. Это всегда путало меня в том, что это такое, сборник всех этих заголовков или что? Теперь, прочитав ответы, могу ли я сказать, что STL - это объектный файл/что-то похожее на объектный файл?

А также я подумал, где можно прочитать определения функций таких функций, как pow(), sqrt() и т.д. Я бы открыл файлы заголовков и ничего не нашел. Итак, определение функции в библиотеке в двоичной нечитабельной форме?

4b9b3361

Ответ 1

Исходный файл AC проходит через две основные стадии: (1) этап препроцессора, где исходный код C обрабатывается программой препроцессора, которая ищет директивы препроцессора и выполняет эти действия, и (2) этап компиляции, где обработанный источник C тогда код фактически скомпилирован для создания файлов объектных кодов.

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

Файл не должен быть исходным кодом C, потому что препроцессор выполняет манипуляции с текстом. Я видел, что C Preprocssor используется для расширения утилиты make, позволяя включить директивы preprossor в файл make. Файл make с директивами C Preprocessor запускается через служебную программу C Preprocessor, а полученный результат затем подается в make, чтобы выполнить фактическую сборку целевой цели.

Библиотеки и ссылки

Библиотека - это файл, содержащий объектный код различных функций. Это способ пакетного вывода из нескольких исходных файлов, когда они скомпилированы в один файл. Многократно предоставляется файл библиотеки вместе с файлом заголовка (включая файл), как правило, с расширением .h файла. Заголовочный файл содержит декларации функций, объявления глобальных переменных, а также директивы препроцессора, необходимые для библиотеки. Таким образом, чтобы использовать библиотеку, вы включаете заголовочный файл, предоставляемый с помощью директивы #include, и вы связываетесь с файлом библиотеки.

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

Существует два типа библиотек, которые обычно используются. Первый и более старый тип - это статическая библиотека. Вторая и последняя - динамическая библиотека (Dynamic Link Library или DLL в Windows и Shared Library или SO в Linux). Разница между ними заключается в том, что функции в библиотеке привязаны к исполняемому файлу, который использует файл библиотеки.

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

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

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

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

Резюме компиляции и ссылки

Итак, основной процесс компиляции и ссылки программы C:

  • утилита препроцессора генерирует исходный код C

    Компилятор
  • компилирует исходный код C в объектный код, генерируя набор объектных файлов

  • linker связывает различные объектные файлы вместе с любыми библиотеками в исполняемый файл

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

Загружатель

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

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

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

Точки входа и время выполнения C

Последний вопрос - это время выполнения C и main() и исполняемая точка входа.

C Runtime - это объектный код, предоставленный производителем компилятора, который содержит точку входа для приложения, написанного на C. Функция main() - это точка входа, предоставленная программистом, записывающим приложение, однако это не запись укажите, что видит загрузчик. Функция main() вызывается C Runtime после запуска приложения, а код C Runtime устанавливает среду для приложения.

C Runtime не является стандартной библиотекой C. Цель C Runtime - управлять средой выполнения для приложения. Цель Стандартной библиотеки C состоит в том, чтобы предоставить набор полезных служебных функций, чтобы программисту не приходилось создавать свои собственные.

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

Ответ 2

Это чрезвычайно распространенный источник путаницы. Я думаю, что самый простой способ понять, что происходит, - это простой пример. Забудьте о библиотеках на мгновение и рассмотрите следующее:

$ cat main.c
extern int foo( void );
int main( void ) { return foo(); }
$ cat foo.c
int foo( void ) { return 0; }
$ cc -c main.c
$ cc -c foo.c
$ cc main.o foo.o

Объявление extern int foo( void ) выполняет точно ту же функцию, что и заголовочный файл библиотеки. foo.o выполняет функцию библиотеки. Если вы понимаете этот пример и почему ни cc main.c, ни cc main.o не работают, тогда вы понимаете разницу между файлами заголовков и библиотеками.

Ответ 3

Да, почти правильно. За исключением того, что компоновщик не связывает объектные файлы, а также библиотеки - в этом случае это стандартная библиотека C (libc) - это то, что связано с вашим объектным файлом. Остальные ваши предположения, похоже, верны в отношении этапов компиляции + разницы между заголовком и библиотекой.