Включая один исходный файл C в другой?
Это нормально (или даже рекомендуется / хорошая практика) #include
Файл.c в другом файле.c? Что происходит, когда они включены в файл проекта?
10 ответов
При правильном использовании это может быть полезным методом.
Допустим, у вас есть сложная, критичная к производительности подсистема с довольно небольшим общедоступным интерфейсом и большим количеством кода многократного использования. Код состоит из нескольких тысяч строк, сотен или около того приватных функций и совсем немного приватных данных. Если вы работаете с нетривиальными встроенными системами, вы, вероятно, сталкиваетесь с этой ситуацией достаточно часто.
Ваше решение, вероятно, будет многоуровневым, модульным и отделенным, и эти аспекты могут быть с пользой представлены и усилены путем кодирования различных частей подсистемы в разных файлах.
С этим вы можете многое потерять. Почти все наборы инструментов обеспечивают достойную оптимизацию для одного модуля компиляции, но очень пессимистично относятся ко всему объявленному extern.
Если вы поместите все в один исходный модуль C, вы получите -
Улучшения производительности и размера кода - во многих случаях вызовы функций будут встроены. Даже без включения компилятор имеет возможность создавать более эффективный код.
Данные уровня связи и функции сокрытия.
Избежание загрязнения пространства имен и его следствия - вы можете использовать менее громоздкие имена.
Более быстрая компиляция и связь.
Но вы также получаете нечестивый беспорядок, когда дело доходит до редактирования этого файла, и вы теряете подразумеваемую модульность. Этого можно избежать, разделив исходный код на несколько файлов и включив их в один модуль компиляции.
Вы должны навязать некоторые соглашения, чтобы справиться с этим, хотя. Это будет зависеть от вашего набора инструментов в некоторой степени, но некоторые общие указатели -
Поместите публичный интерфейс в отдельный заголовочный файл - вы все равно должны это делать.
Иметь один основной файл.c, который включает все вспомогательные файлы.c. Это может также включать код для открытого интерфейса.
Используйте средства защиты компилятора, чтобы убедиться, что частные заголовки и исходные модули не включены внешними модулями компиляции.
Все личные данные и функции должны быть объявлены как статические.
Сохраняйте концептуальное различие между файлами.c и.h. Это использует существующие соглашения. Разница в том, что у вас будет много статических объявлений в заголовках.
Если ваша цепочка инструментов не навязывает никаких причин, не называйте частные файлы реализации как.c и.h. Если вы используете встроенные средства защиты, они не будут генерировать код и не будут вводить новые имена (вы можете получить пустые сегменты во время связывания). Огромным преимуществом является то, что другие инструменты (например, IDE) будут обрабатывать эти файлы соответствующим образом.
Это нормально? да, это скомпилирует
это рекомендуется? no - файлы.c компилируются в файлы.obj, которые после компиляции (компоновщиком) связываются в исполняемый файл (или библиотеку), поэтому нет необходимости включать один файл.c в другой. Вместо этого вы, вероятно, захотите сделать файл.h, в котором перечислены функции / переменные, доступные в другом файле.c, и включить файл.h.
Нет.
В зависимости от вашей среды сборки (вы не указываете), вы можете обнаружить, что она работает именно так, как вы хотите.
Однако во многих средах (как в среде IDE, так и во многих созданных вручную файлах Makefile) ожидается компиляция *.c - если это произойдет, вы, вероятно, получите ошибки компоновщика из-за повторяющихся символов.
Как правило, этой практики следует избегать.
Если вам абсолютно необходимо #include source (и, как правило, этого следует избегать), используйте для файла другой суффикс файла.
Вы можете использовать компилятор 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 storage.
Я думал, что поделюсь ситуацией, когда моя команда решила включить файлы.c. Наша структура в основном состоит из модулей, которые отделены через систему сообщений. Эти обработчики сообщений являются общедоступными и для выполнения своей работы вызывают множество локальных статических рабочих функций. Проблема возникла при попытке получить покрытие для наших тестов модульных тестов, поскольку единственный способ реализовать этот частный код реализации был косвенно через интерфейс общедоступных сообщений. С некоторыми рабочими функциями по колено в стеке, это оказалось кошмаром для достижения надлежащего покрытия.
Включение файлов.c дало нам возможность добраться до винтика на машине, которую мы интересовали в тестировании.
Расширение файла не имеет значения для большинства компиляторов Си, поэтому оно будет работать.
Однако, в зависимости от вашего make-файла или настроек проекта, включенный файл c может генерировать отдельный объектный файл. При связывании это может привести к двойному определению символов.
Вы можете правильно включать файлы.C или.CPP в другие исходные файлы. В зависимости от вашей среды IDE, вы обычно можете предотвратить двойное связывание, посмотрев свойства исходных файлов, которые вы хотите включить, обычно щелкнув правой кнопкой мыши по нему и выбрав свойства, и снимите флажок / установите флажок compile / link / exclude from build или любую другую опцию может быть. Или вы не можете включить файл в сам проект, поэтому IDE даже не узнает, что он существует, и не будет пытаться скомпилировать его. А с make-файлами вы просто не поместите файл в него для компиляции и компоновки.
РЕДАКТИРОВАТЬ: Извините, я сделал это ответ вместо ответа на другие ответы:(
Включение файла C в другой файл - это законно, но не рекомендуется, если вы точно не знаете, почему вы это делаете и чего пытаетесь достичь.
Я почти уверен, что если вы опубликуете здесь причину того, что за вашим вопросом сообщество найдет вам другой более подходящий способ достижения вашей цели (обратите внимание на "почти", так как возможно, что это решение, учитывая контекст).
Кстати, я пропустил вторую часть вопроса. Если файл C включен в другой файл и в то же время включен в проект, вы, вероятно, столкнетесь с проблемой дублирования символов, почему связывание объектов, то есть одна и та же функция, будет определено дважды (если только они не статичны).
Во многих других ответах более чем описано, как вы можете это сделать, но почему вы, вероятно, не должны этого делать в обычных обстоятельствах. Тем не менее, я добавлю, почему я делал это в прошлом.
При разработке встраиваемых систем исходный код поставщика микросхем обычно является частью ваших скомпилированных файлов. Проблема в том, что у этих поставщиков, вероятно, нет тех же руководств по стилю или стандартных настроек флагов предупреждений / ошибок, что и у вашей организации.
Таким образом, вы можете создать локальный исходный файл, который включает исходный код поставщика, а затем вместо этого скомпилировать этот файл оболочки C для подавления любых проблем во включенном источнике, а также любых заголовков, включенных в этот источник. В качестве примера:
/**
* @file vendor_wrap.c
* @brief vendor source code wrapper to prevent warnings
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnested-externs"
#include "vendor_source_code.c"
#pragma GCC diagnostic pop
Это позволяет использовать менее сложные сценарии Make со стандартным набором флагов и настроек компилятора с определенными исключениями в коде, а не иметь собственные флаги для некоторых файлов в сценарии.
gcc main.c vendor_wrap.c -o $(CFLAGS) main.out
Язык C не запрещает такого рода #include, но полученная единица перевода все еще должна быть допустимой C.
Я не знаю, какую программу вы используете с файлом.prj. Если вы используете что-то вроде "make", Visual Studio или что-то еще, просто убедитесь, что вы установили список файлов для компиляции без того, который не может компилироваться независимо.
Вы должны добавить заголовок, как это
#include <another.c>
примечание: оба файла должны быть размещены в одном месте