Включая один исходный файл C в другой? - PullRequest
95 голосов
/ 24 октября 2008

Это нормально (или даже рекомендуется / хорошая практика) для #include .c файла в другом .c файле? Что происходит, когда они включены в файл проекта?

Ответы [ 10 ]

105 голосов
/ 10 июля 2009

При правильном использовании это может быть полезной техникой.

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

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

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

Если вы поместите все в один исходный модуль C, вы получите -

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

  • Данные уровня связи и скрытие функций.

  • Предотвращение загрязнения пространства имен и его следствия - вы можете использовать менее громоздкие имена.

  • Более быстрая компиляция и связывание.

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

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

  • Поместите публичный интерфейс в отдельный заголовочный файл - вы все равно должны это делать.

  • Имеется один основной файл .c, который включает все вспомогательные файлы .c. Это также может включать код для открытого интерфейса.

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

  • Все личные данные и функции должны быть объявлены как статические.

  • Сохранение концептуального различия между файлами .c и .h. Это использует существующие соглашения. Разница в том, что у вас будет много статических объявлений в заголовках.

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

49 голосов
/ 24 октября 2008

это нормально? да, это скомпилирует

это рекомендуется? no - файлы .c компилируются в файлы .obj, которые после компиляции (компоновщиком) связываются в исполняемый файл (или библиотеку), поэтому нет необходимости включать один файл .c в другой. Вместо этого вы, вероятно, захотите сделать файл .h, в котором перечислены функции / переменные, доступные в другом файле .c, и включить файл .h

11 голосов
/ 24 октября 2008

номер

В зависимости от вашей среды сборки (вы не указываете), вы можете обнаружить, что она работает именно так, как вы хотите.

Однако во многих средах (как в среде IDE, так и во многих созданных вручную файлах Makefile) ожидается компиляция * .c - если это произойдет, вы, вероятно, получите ошибки компоновщика из-за повторяющихся символов.

Как правило, этой практики следует избегать.

Если вам абсолютно необходимо #include source (и, как правило, этого следует избегать), используйте для файла другой суффикс файла.

9 голосов
/ 05 октября 2010

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

Включение файлов .c дало нам возможность добраться до винтика на машине, которую мы интересовали в тестировании.

5 голосов
/ 24 октября 2008

Расширение файла не имеет значения для большинства компиляторов Си, поэтому оно будет работать.

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

3 голосов
/ 21 августа 2016

Вы можете использовать компилятор gcc в linux, чтобы связать два файла c в одном выводе. Предположим, у вас есть два файла c, один из которых 'main.c', а другой 'support.c'. Таким образом, команда связать эти два -

gcc main.c support.c -o main.out

При этом два файла будут связаны с одним выходом main.out Для запуска вывода команда будет

./main.out

Если вы используете функцию из main.c, которая объявлена ​​в файле support.c, то вы должны объявить ее в main также с использованием класса хранения extern.

2 голосов
/ 10 июля 2014

Вы можете правильно включать файлы .C или .CPP в другие исходные файлы. В зависимости от вашей среды IDE, вы обычно можете предотвратить двойное связывание, посмотрев свойства исходных файлов, которые вы хотите включить, обычно щелкнув правой кнопкой мыши по нему и выбрав свойства, и снимите флажок / отметьте compile / link / exclude from build или любую другую опцию может быть. Или вы не можете включить файл в сам проект, поэтому IDE даже не узнает, что он существует, и не будет пытаться скомпилировать его. А с make-файлами вы просто не поместите файл в него для компиляции и компоновки.

РЕДАКТИРОВАТЬ: Извините, я сделал это ответ вместо ответа на другие ответы: (

1 голос
/ 24 октября 2008

Язык C не запрещает такого рода #include, но итоговая единица перевода по-прежнему должна быть действительной C.

Я не знаю, какую программу вы используете с файлом .prj. Если вы используете что-то вроде «make», Visual Studio или что-то еще, просто убедитесь, что вы установили список файлов для компиляции без того, который не может компилироваться независимо.

0 голосов
/ 15 августа 2016

Вы должны добавить заголовок, как это

#include <another.c>

примечание: оба файла должны быть размещены в одном месте

0 голосов
/ 24 октября 2008

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

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

...