2017-01-29 2 views
7

Если мы имеем два .c файлы и .h файл: main.c sub.c sub.h, гдеC: уточнение на ЕП

main.c

#include "sub.h" 
... 

sub.c

#include "sub.h" 
... 

мы можем скомпилировать программу с помощью i)

gcc -o a.out main.c sub.c 

или б)

gcc -c main.c 
gcc -c sub.c 
gcc -o a.out main.o sub.o 

Учитывая этот случай, делает модуль вывода препроцессора один или два перевода (ы)?

Я смущен, потому что: main.c включает в себя sub.h, что означает, что препроцессор выводит один блок компиляции. С другой стороны, перед созданием исполняемого файла создаются два объектных файла: main.o и sub.o, что заставляет меня думать, что «два исходных файла, таким образом, два единицы перевода».

Какую часть я недопонимаю? или где я делаю ошибки?

ответ

3

Вот что стандарт C должен сказать о том, что:

Исходный файл вместе со всеми заголовками и исходных файлов, включенных с помощью директивы препроцессора #include известен как блок предварительной обработки перевода. После предварительной обработки блок перевода с предварительной обработкой называется единицей трансляции. [..] Ранее переведенный перевод единиц можно сохранить отдельно или в библиотеках.Отдельные единицы перевода программы связывают (например) вызовы функций, чьи идентификаторы имеют внешнюю связь, манипулирование объектами, чьи идентификаторы имеют внешнюю связь, или манипулирование файлами данных. Единицы перевода могут быть переведены отдельно, а затем связаны для создания исполняемой программы.

(Источник: C99 проект стандарта 5.1.1.1 § 1)

Таким образом, в обоих случаях ваши у вас есть две единицы перевода. Один из них исходит из предварительной обработки компилятора main.c и всего, что включено в директивы #include —, то есть sub.h и, возможно, <stdio.h> и другие заголовки. Второй - от компилятора, делающего то же самое с sub.c.

Отличие от вашего первого к вашему второму примеру состоит в том, что в последнем вы явно храните «разные переведенные единицы перевода» в качестве объектных файлов.

Обратите внимание, что не существует правила, связывающего один объектный файл с любым количеством единиц перевода. Компонент GNU является одним из примеров компоновщика, который is capable of joining two .o files together.

Стандарт, насколько мне известно, не указывает расширение исходных файлов. Тем не менее, в практических аспектах вы можете бесплатно загрузить #include файл .c в другой или разместить всю программу в файле .h. С помощью gcc вы можете использовать опцию -x c, чтобы заставить файл .h рассматриваться как отправную точку единицы перевода.

Различие сделано здесь:

Исходный файл вместе со всеми заголовками и исходных файлов, включенных с помощью директивы препроцессора #include [...]

потому, что заголовок не должен быть исходный файл. Точно так же содержимое <...> в директиве #include не должно быть допустимым именем файла. Как именно компилятор использует именованные заголовки <...> и "..." является реализацией.

6

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

«Единица перевода» - это вопрос первого шага. Единица перевода - это каждый файл, в котором начинается компиляция (т.е. передается компилятору). В большинстве IDE существуют правила, объявляющие, что каждый файл с расширением .c или .cpp передается в качестве входных данных для компилятора, тогда как других файлов нет. Поэтому файлы с расширением .h, .hpp, .txt обычно не передаются непосредственно компилятору.

В вашем примере, main.c и sub.c, вероятно, единицы перевода, в то время как sub.h не единица перевода сам по себе (это только «включено» в других единицах перевода и рассматриваются в процессе их составления).

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

Обратите внимание, что даже файл .h может содержать полную программу; но если вы не настроите среду, которую этот файл .h скомпилирован сам по себе, он не будет генерировать объектный файл.