Базовая структура проекта C / C ++ (заголовочные файлы и файлы cpp) - PullRequest
3 голосов
/ 07 октября 2010

Это вопрос для новичка, зашедшего в тупик, но здесь он звучит так:

Что определяет, какие файлы включаются в проект C / C ++?

Насколько я понимаю, компилятор начинается сфайл, в котором есть main () и который будет содержать # include для получения различных h-файлов, которые содержат # include для других h-файлов и т. д., пока все не будет включено в проект.

Мои вопросы:

Какая связь между h-файлами и cpp-файлами с одинаковыми именами?Я имею в виду, конечно, что я понимаю, что по коду они нуждаются друг в друге, и файл cpp всегда (почти всегда?) # Включает в себя файл h, но с точки зрения компилятора важно, чтобы они имели одинаковые имена илиэто все просто условность?Могу ли я включить дополнительные файлы cpp без соответствующих h-файлов?

Кроме того, когда проект создается и связывается, как он узнает, для каких файлов cpp / h создаются объектные файлы?Будет ли он просто начинаться с файла cpp с «main ()» в нем и продолжаться через # include до тех пор, пока у него не будет все, что ему нужно, и собрать все это, или он просто создаст все, что пользователь указывает в make-файле или вФайл проекта IDE?

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

Любая помощь, подсказки,объяснения приветствуются .. Спасибо!

- R

Ответы [ 4 ]

1 голос
/ 07 октября 2010

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

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

Обычно вы включаете часть своего приложения (например, общий слой доступа к базе данных) в отдельный исходный файл, такой как db.cpp, и создаете файл db.h с его API. Этот файл не столько используется db.cpp, сколько используется всеми другими файлами, которые должны вызывать функции в db.cpp. Он может быть может быть включен в db.cpp, но в основном это публикуемая информация о коде db.

Относительно того, как среда определяет, какие вещи нужно скомпилировать / связать: у вас есть какой-то проект (makefile, файл проекта IDE и т. Д.), В котором перечислены все программы, которые вы хотите скомпилировать (обычно это не заголовочные файлы). ).

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

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

1 голос
/ 07 октября 2010

Небольшая охота в сети получит много вашего ответа.Вот только два: http://www.psgd.org/paul/docs/cstyle/cstyle02.htm

http://www.cs.utexas.edu/~lavender/courses/EE360C/lectures/lecture-02.pdf

Второй вариант довольно хорош.

Я бы также порекомендовал 3-й выпуск языка программирования c ++.Есть отличный раздел об организации файлов.

Что касается того, что делает компилятор, это тоже лучше всего объяснить в отдельной статье.Короче говоря, каждый файл cpp компилируется в модуль перевода (объектный код), затем компоновщик соединяет все вместе в конечный исполняемый файл.

0 голосов
/ 07 октября 2010

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

Тем не менее, любые нетривиальные проекты опираются на символы (переменные, функции), определенные в других библиотеках, даже если только для таких вещей, как malloc (), socket (), file (), write () и т. Д., Предоставляемых языком или стандартные библиотеки операционной системы. Даже если вы не вызываете их напрямую, они нужны для реализации таких вещей, как new и iostream.

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

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

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

Файлы реализации (cpp) должны почти всегда сначала включать свой заголовочный файл, потому что компилятор тогда будет жаловаться, если есть некоторая несоответствие между содержимым объекта, которое он создает, и объявленным файлом заголовочного файла содержимым, которое код, использующий объект, позже будет ожидать , Для некоторых вещей, таких как классы, объявление класса должно просматриваться до того, как может быть указана реализация функции-члена, и, учитывая, что объявление класса необходимо клиентскому коду и, следовательно, в заголовке, на практике реализация также должна включать заголовок. (Я говорю, что cpp должен включать свой заголовок first , потому что компилятор потом будет жаловаться, если заголовок полагается на некоторый контент, который он не включает сам. В противном случае, если, скажем, cpp включает заголовок std :: string и заголовок использует его, но какой-то другой клиентский код пытается включить заголовок без включения строки, тогда компиляция завершится неудачей).

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

0 голосов
/ 07 октября 2010

Заголовочный файл - это, по сути, предварительное объявление класса и всех его атрибутов и функций-членов, это сделает ваш класс более пригодным для повторного использования и более доступным. Думайте об этом как об интерфейсе, свободном от реализации, поэтому любому, кто его использует, не нужно беспокоиться об источнике для этого конкретного класса. Из того, что я знаю, соответствующие h-файлы и cpp-файлы должны иметь одинаковые имена. Файл cpp не всегда должен иметь соответствующий h-файл, вы можете иметь все свои исходные тексты в одном cpp-файле без h-файлов и при условии, что все реализовано правильно и правильно прототипировано, все должно работать нормально.

...