Ответы:
При правильном использовании это может оказаться полезным методом.
Допустим, у вас есть сложная подсистема, критичная к производительности, с довольно небольшим общедоступным интерфейсом и большим количеством не подлежащего повторному использованию кода реализации. Код состоит из нескольких тысяч строк, сотни или около того частных функций и довольно много частных данных. Если вы работаете с нетривиальными встроенными системами, вы, вероятно, достаточно часто сталкиваетесь с этой ситуацией.
Ваше решение, вероятно, будет многоуровневым, модульным и разделенным, и эти аспекты могут быть с пользой представлены и усилены путем кодирования различных частей подсистемы в разных файлах.
С C вы можете многое потерять, сделав это. Почти все инструментальные средства обеспечивают достойную оптимизацию для одной единицы компиляции, но очень пессимистично относятся к любому объявлению extern.
Если вы поместите все в один исходный модуль C, вы получите -
Улучшения производительности и размера кода - во многих случаях вызовы функций будут встроены. Даже без встраивания у компилятора есть возможности для создания более эффективного кода.
Скрытие данных и функций на уровне ссылок.
Избежание загрязнения пространства имен и его следствия - вы можете использовать менее громоздкие имена.
Более быстрая компиляция и компоновка.
Но вы также получаете нечестивую путаницу, когда дело касается редактирования этого файла, и вы теряете подразумеваемую модульность. Это можно преодолеть, разделив исходный код на несколько файлов и включив их для создания единой единицы компиляции.
Тем не менее, вам необходимо ввести некоторые соглашения, чтобы управлять этим должным образом. Это в некоторой степени будет зависеть от вашей инструментальной цепочки, но некоторые общие указания:
Поместите публичный интерфейс в отдельный файл заголовка - вы все равно должны это делать.
Имейте один основной файл .c, который включает все вспомогательные файлы .c. Это также может включать код для общедоступного интерфейса.
Используйте средства защиты компилятора, чтобы гарантировать, что частные заголовки и исходные модули не включены во внешние модули компиляции.
Все частные данные и функции должны быть объявлены статическими.
Сохраняйте концептуальное различие между файлами .c и .h. Это усиливает существующие соглашения. Разница в том, что в ваших заголовках будет много статических объявлений.
Если в вашей инструментальной цепочке нет причин не делать этого, назовите частные файлы реализации как .c и .h. Если вы используете include guards, они не будут производить код и не вводить новые имена (вы можете получить некоторые пустые сегменты во время связывания). Огромным преимуществом является то, что другие инструменты (например, IDE) будут обрабатывать эти файлы соответствующим образом.
Это нормально? да, он будет компилироваться
это рекомендуется? no - файлы .c компилируются в файлы .obj, которые после компиляции (компоновщиком) связываются вместе в исполняемый файл (или библиотеку), поэтому нет необходимости включать один файл .c в другой. Вместо этого вы, вероятно, захотите создать файл .h, в котором перечислены функции / переменные, доступные в другом файле .c, и включить файл .h
Нет.
В зависимости от вашей среды сборки (вы не указываете), вы можете обнаружить, что она работает именно так, как вы хотите.
Однако существует множество сред (как IDE, так и множество созданных вручную Makefile), которые ожидают компиляции * .c - если это произойдет, вы, вероятно, получите ошибки компоновщика из-за повторяющихся символов.
Как правило, такой практики следует избегать.
Если вам абсолютно необходимо #include source (и обычно этого следует избегать), используйте для файла другой суффикс.
Я подумал, что поделюсь ситуацией, когда моя команда решила включить файлы .c. Наш архив в основном состоит из модулей, разделенных системой сообщений. Эти обработчики сообщений являются общедоступными и вызывают многие локальные статические рабочие функции для выполнения своей работы. Проблема возникла при попытке охватить наши примеры модульного тестирования, поскольку единственный способ реализовать этот частный код реализации - косвенно через интерфейс общедоступных сообщений. С некоторыми рабочими функциями по колено в стеке, это оказалось кошмаром для достижения надлежащего покрытия.
Включение файлов .c дало нам возможность добраться до винтика в машине, которую мы интересовали в тестировании.
Вы можете использовать компилятор 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.
Вы можете правильно включать файлы .C или .CPP в другие исходные файлы. В зависимости от вашей IDE вы обычно можете предотвратить двойную привязку, просмотрев свойства исходных файлов, которые вы хотите включить, обычно щелкнув правой кнопкой мыши по нему и щелкнув свойства, а также снимите / отметьте компиляцию / ссылку / исключить из сборки или любой другой вариант, который он может быть. Или вы не можете включить файл в сам проект, поэтому IDE даже не узнает о его существовании и не попытается его скомпилировать. А с make-файлами вы просто не поместите файл в него для компиляции и компоновки.
РЕДАКТИРОВАТЬ: Извините, я сделал это ответом вместо ответа на другие ответы :(
Язык C не запрещает такие #include, но полученная единица перевода все равно должна быть действительной C.
Я не знаю, какую программу вы используете с файлом .prj. Если вы используете что-то вроде «make», Visual Studio или что-то еще, просто убедитесь, что вы установили его список файлов для компиляции без того, который не может компилироваться независимо.
Включение файла C в другой файл является законным, но не рекомендуется, если вы точно не знаете, почему вы это делаете и чего пытаетесь достичь.
Я почти уверен, что если вы опубликуете здесь причину, по которой за вашим вопросом сообщество найдет вам другой, более подходящий способ достижения вашей цели (обратите внимание на «почти», поскольку возможно, что это решение, учитывая контекст ).
Кстати, я пропустил вторую часть вопроса. Если файл C включен в другой файл и в то же время включен в проект, вы, вероятно, столкнетесь с проблемой дублирования символов, почему связываются объекты, т.е. одна и та же функция будет определена дважды (если все они статичны).