Online Включая один исходный файл C в другой? Что должно быть в с-файле, а что должно быть в h-файле? Исходный файл c



vote online (8)

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

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

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

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

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

Тем не менее, существует множество сред (как IDE, так и много обработанных вручную Makefile), которые ожидают компиляции * .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, тогда вы должны объявить ее в основном также с использованием класса extern storage.

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

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

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

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

Используемый правильно, это может быть полезным методом.

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

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

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

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

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

    Данные уровня канала и функции скрываются.

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

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

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

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

    Поместите открытый интерфейс в отдельный файл заголовка - вы все равно должны это делать.

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

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

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

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

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

Это нормально? да, он будет компилировать

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



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

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

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

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

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

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

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

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

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

Gcc main.c support.c -o main.out

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

./main.out

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

Используемый правильно, это может быть полезным методом.

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

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

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

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

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

    Данные уровня канала и функции скрываются.

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

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

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

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

    Поместите открытый интерфейс в отдельный файл заголовка - вы все равно должны это делать.

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

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

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

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

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

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

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

вы должны добавить заголовок, подобный этому

#include

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

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

EDIT: Извините, я дал ответ вместо ответа на другие ответы:(

Программирование Козлова Ирина Сергеевна

27. Исходные файлы С++

27. Исходные файлы С++

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

extern double sqrt(double); extern instream cin;

Самый простой способ обеспечить согласованность исходных файлов – помещение таких же описаний в отдельные файлы, которые называются заголовочными (или хэдер) файлами, после чего включить, т. е. скопировать, эти заголовочные файлы во все файлы, где необходимы эти описания. К примеру, если описание sqrt располагается в заголовочном файле для стандартных математических функций math.h и необходимо извлечь квадратный корень из 4, следует применить программу:

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

В команде включения include имя файла, которое располагается в угловых скобках, например, относится к файлу с таким именем в стандартном каталоге (обычно это /usr/include/CC); на файлы, хранящиеся в других местах, ссылаются, применяя имена, расположенные в двойных кавычках. Например:

#include «math1.h» #include «/usr/bs/math2.h»

включит math1.h из текущего пользовательского каталога, а math2.h из каталога /usr/bs.

Покажем, как мы могли бы определить тип потока вывода ostream. Для упрощения задачи предположим, что для буферизации определен тип streambuf. Тип streambuf определен в том месте, где также располагается и настоящее определение ostream. Значение типа, определяемого пользователем, специфицирует данные, которые нужны для представления объекта этого типа, и большое число операций для работы с этими объектами. Определение состоит из двух частей: закрытой (private) части, в которой находится информация, используемая только его разработчиком, и открытой (public) части, являющейся интерфейсом типа с пользователем.

Из книги Программы и файлы Windows автора Климов А

DBX-файлы В файлах с расширением DBX хранятся записи программы Outlook Express. В этих файлах, называемых Банком сообщений, находятся письма, сообщения новостных групп и т.п. При желании, можно скопировать эти файлы на носитель информации для переноса данных в другой компьютер.

Из книги Программирование автора Козлова Ирина Сергеевна

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

Из книги Win2K FAQ (v. 6.0) автора Шашков Алексей

12. Комментарии. Исходные файлы Комментарием является набор символов, игнорируемых компилятором. Но на данный набор символов накладываются определенные ограничения. Внутри набора символов, представляющих комментарий, не может быть специальных символов, которые

Из книги Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT автора Фролов Александр Вячеславович

27. Исходные файлы С++ Программа на C++ чаще всего включает в себя большое число исходных файлов, в каждом из которых находятся описания типов, функций, переменных и констант. Чтобы имя можно было применять в разных исходных файлах для ссылки на определенный объект, оно

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

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

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.

Из книги КОМПАС-3D для студентов и школьников. Черчение, информатика, геометрия автора Большаков Владимир

Из книги Недокументированные и малоизвестные возможности Windows XP автора Клименко Роман Александрович

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

Из книги Программирование для Linux. Профессиональный подход автора Митчелл Марк

Приложение 2 Исходные данные для твердотельного моделирования

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард

Приложение 3 Исходные данные для моделирования семейств

Из книги Wiki-правительство [Как технологии могут сделать власть лучше, демократию – сильнее, а граждан – влиятельнее] автора Новек Бет

CPL-файлы Из нескольких предыдущих абзацев вы узнали практически все теоретические выкладки, которые необходимы для работы с программой rundll32.exe. Сейчас же будут перечислены те возможности, которые данная программа может предоставить пользователю. Начнем с описания

Из книги UNIX - универсальная среда программирования автора Пайк Роб

1.5.4. Исходные тексты Linux - система с открытым кодом, не так ли? Верховным судьей, определяющим, как работает система, является исходный код самой системы. К нашему счастью, он доступен бесплатно. В имеющийся дистрибутив Linux могут входить исходные тексты всей системы и всех

Из книги автора

А.3.5. Исходные тексты программы-калькулятора В листинге А.3 показан текст программы, вычисляющей значения постфиксных выражений.Листинг А.3. (calculator.c) Основная часть программы-калькулятора/* Вычисления в унарном формате. *//* На вход программы подаются однострочные

Из книги автора

Приложение Г Различные исходные коды Г.1. Заголовочный файл unp.h Почти каждая программа в этой книге начинается с подключения заголовочного файла unp.h, показанного в листинге Г.1. Этот файл подключает все стандартные системные заголовочные файлы, необходимые для работы

Из книги автора

Из книги автора

Приложение 3 Исходные тексты калькулятора hoc These files contain all the code from "The Unix Programming Environment", by Brian Kernighan and Rob Pike (Prentice Hall, 1984, ISBN 0-13-937681-X). A separate hoc6 distribution contains any fixes that we have applied to that; the version in this file is from the book.Copyright © Lucent Technologies, 1997. All Rights ReservedPermission to use, copy, modify, and distribute this software and its documentation for

Исходные файлы

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

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

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

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

В нижеследующем примере исходная программа состоит из двух исходных файлов. Функции main и max представлены в отдельных файлах. Функция main использует функцию max в процессе своего выполнения.

/* исходный файл 1 - функция main */

extern int max (int, int); /* объявление функции */

main () /* определение функции */

int w = ONE, x = TWO, у = THREE;

/* исходный файл 2 - функция max */

int max (a, b) /* определение функции */

В первом исходном файле функция max объявлена, но не определена. Такое объявление функции называется предварительным; оно позволяет компилятору контролировать обращение к функции до того, как она определена. Определение функции main содержит вызовы функции max .

Строки, начинающиеся с символа #, являются директивами препроцессора. Директивы указывают препроцессору на необходимость замены в первом исходном файле идентификаторов ONE, TWO, THREE на соответствующие значения. Область действия директив не распространяется на второй исходный файл.

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

Отчасти это дело вкуса, поэтому, кому интересно как это делаю я, добро пожаловать под кат.

Несмотря на то, что «вся правда» о h-файлах содержится в соответствующем разделе описания препроцессора gcc, позволю себе некоторые пояснения и иллюстрации.

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

Легко заметить, что функции 1 и 2, а так же макрос 2, упомянуты в обоих файлах. И, поскольку, включение заголовочных файлов приводит к таким же результатам, как и копирование содержимого в каждый си-файл, мы можем сделать следующее:

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

  • Если нам нужно использовать функциональность, которую реализуют функции 1 и 2 где то еще, то Да
  • Если макрос 2, предназначен только для использования в файлах Unit1.c и Unit2.c, то ему не место в интерфейсном файле
Более того, действительно ли нам необходимо иметь два си-файла для реализации интерфейса, определенного в заголовочном файле? Или достаточно одного?
Ответ на этот вопрос зависит от деталей реализации интерфейсных функций и от их места реализации. Например, если сделать диаграммы более подробными, можно представить вариант, когда интерфейсные функции реализованы в разных файлах:


Такой вариант реализации приводит к высокой связности кода, низкой тестируемости и к сложности повторного использования таких модулей.
Для того, что бы не иметь таких трудностей, я всегда рассматриваю си-файл и заголовочный файл как один модуль. В котором,
  • заголовочный файл содержит только те декларации функций, типов, макросов, которые являются частью интерфейса данного модуля.
  • Си-файл, в свою очередь, должен содержать реализацию всех функций, декларированных в h- файле, а также приватные типы, макросы и функции, которые нужны для реализации интерфейса.
Таким образом, если бы мне довелось реализовывать код, которому соответствует диаграмма приведенная выше, я бы постарался, добиться следующего (окончания _с и _h в именах файлов добавлены по причине невозможности использовать точку в инструменте , которым я пользовался для создания диаграмм):


Из диаграммы видно, что на самом деле мы имеем дело с двумя независимыми модулями, у каждого из которых имеется свой интерфейс в виде заголовочного файла. Это дает возможность использовать только тот интерфейс, который действительно необходим в данном конкретном случае.Более того, эти модули могут быть протестированы независимо друг от друга.
Читатель, наверное, заметил, что макрос 2 из заголовочного файла снова вернулся в виде копии в оба си-файла. Конечно, это не очень удобно поддерживать. Но и делать данный макрос частью интерфейса не правильно.
В таких случаях, я предпочитаю делать отдельный заголовочный файл содержащий типы и макросы, необходимые нескольким си-файлам.

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

Спасибо за внимание к материалу.

Инструкции