реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Проект из многих файлов на C, Как использовать заголовочные файлы?
ViKo
сообщение Mar 23 2014, 06:57
Сообщение #1


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Давно терзаюсь вопросами.
Имею проект из нескольких c-файлов. Один из них - главный, main.c, в остальных - некие функции (как разбить проект на части - тоже вопрос смутный, как и понятия "драйвер", "core").
Чтобы функции могли вызываться из любого файла, нужно описать их прототипы. Я их описываю в заголовочных h-файлах, соответствующих c-файлам (display.c - display.h). А чтобы не включать всю кучу h-файлов во все c-файлы, собрал их в одну кучу в main.h. Вот его и включаю во все c-файлы (и в main.c тоже). Где-то видел, такие h-файлы называются "helper".
Чтобы h-файлы не включались в проект по нескольку раз, заключаю все содержимое в макроопределения:
Код
#ifndef DISPLAY_H
#define DISPLAY_H
...
#endif

Также есть отдельные h-файлы, для частных включений.
С глобальными переменными дело обстоит чуть сложнее. В своем файле они должны быть определены, а в остальных заданы, как extern. Для этого пользуюсь макроопределениями (создал в main.h):
Код
#ifndef VAR_DECLS
#define _DECL extern
#define _INIT(x)
#else
#define _DECL
#define _INIT(x) = x
#endif

Только в одном main.c файле задаю определение #define VAR_DECLS, поэтому все переменные будут определены в main.c, независимо от того, в каком h-файле они описаны.

Не слишком ли я запутываю свои проекты? Например, гложет мысль, как правильнее - использовать display.h в main.h или в display.c?
Поделитесь своими решениями. По каким критериям разбиваете проект на файлы? Где храните переменные?
Как передаете глобальные макроопределения (например, #define BUFF_SIZE 4096)?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 23 2014, 08:12
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(ViKo @ Mar 23 2014, 10:57) *
Не слишком ли я запутываю свои проекты?

По-моему, слишком. Особенно с переменными. Что мешает сделать в main.c:
Код
int global_var = 12345;

А в main.h:
Код
extern int global_var;


Цитата(ViKo @ Mar 23 2014, 10:57) *
...все переменные будут определены в main.c, независимо от того, в каком h-файле они описаны.

Это прямое запутывание: описали в одном месте, а определили в другом, с первым никак очевидно не связанным.
Go to the top of the page
 
+Quote Post
seneka
сообщение Mar 23 2014, 08:14
Сообщение #3


Участник
*

Группа: Свой
Сообщений: 74
Регистрация: 11-03-14
Из: Ростов
Пользователь №: 80 888



Цитата(ViKo @ Mar 23 2014, 10:57) *
Давно терзаюсь вопросами.
Как передаете глобальные макроопределения (например, #define BUFF_SIZE 4096)?


Делаю тоже самое, есть куче локальных файлов *.h, эти локальные файлы прописаны внутри main.h, во всех C файлах прописан только main.h
Как там распределяются назначения особо не вникал, но защиту в виде #ifdef поставить в каждом *.h файле надо.
Ну и все, нужно прописать буфер, объявляйте его где хотите среди заголовочных файлов.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 08:22
Сообщение #4


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(aaarrr @ Mar 23 2014, 11:12) *
Это прямое запутывание: описали в одном месте, а определили в другом, с первым никак очевидно не связанным.

Такого не может быть. Определяется-описывается в одном месте (где угодно, в любом файле, но, очевидно, лучше там, где логичнее) один раз, а попадет во все файлы. Потому что main.h включается во все файлы. Реально определится в main.c, согласно макроопределению _INIT().
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 23 2014, 08:52
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(ViKo @ Mar 23 2014, 12:22) *
Реально определится в main.c, согласно макроопределению _INIT().

Не нужно плодить сущности. Допустим, определению disp_bpp = 16 явно не место в main.c, если есть display.c к которому оно напрямую, а не опосредованно, относится.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 09:15
Сообщение #6


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(aaarrr @ Mar 23 2014, 11:52) *
Не нужно плодить сущности. Допустим, определению disp_bpp = 16 явно не место в main.c, если есть display.c к которому оно напрямую, а не опосредованно, относится.

Правильно. Так ведь я и задам определение в display.h, откуда оно попадет в main.h, откуда попадет в main.c как определение, и в display.c как объявление.
Так избавляюсь от необходимости определять переменную в display.c и объявлять в остальных файлах (или, хотя бы в display.h).
Думаю сделать так же, как вы говорите, в display.c определять переменную, а в display.h объявлять, как extern. Подобно описаниям функций.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 10:18
Сообщение #7


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Тут вот какой вопрос - если бы переменная или макроопределение использовались только в одном файле, то и глобальными их делать незачем. А если не в одном, то в каком...? rolleyes.gif Где, как не в main.h?
Go to the top of the page
 
+Quote Post
dxp
сообщение Mar 23 2014, 10:33
Сообщение #8


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



QUOTE (ViKo @ Mar 23 2014, 13:57) *
Давно терзаюсь вопросами.
<...
А чтобы не включать всю кучу h-файлов во все c-файлы, собрал их в одну кучу в main.h. Вот его и включаю во все c-файлы (и в main.c тоже).

Аналогично, только файл называю не main.h а по имени проекта (<project_name>.h).

QUOTE (ViKo @ Mar 23 2014, 13:57) *
Поделитесь своими решениями. По каким критериям разбиваете проект на файлы? Где храните переменные?

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 10:49
Сообщение #9


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(dxp @ Mar 23 2014, 13:33) *
Аналогично, только файл называю не main.h а по имени проекта (<project_name>.h).

А с-файл как называете - main.cpp или по имени проекта? Тоже колеблюсь туда-сюда. Main найти проще, но смысла меньше.
Помню, за имя Top_m в SV модератор по ПЛИСам намекнул, что отгрыз бы своему "падавану" руки. w00t.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Mar 23 2014, 14:43
Сообщение #10


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(ViKo @ Mar 23 2014, 08:57) *
Не слишком ли я запутываю свои проекты? Например, гложет мысль, как правильнее - использовать display.h в main.h или в display.c?
Поделитесь своими решениями. По каким критериям разбиваете проект на файлы? Где храните переменные?
Как передаете глобальные макроопределения (например, #define BUFF_SIZE 4096)?


Нет не запутываете, вы просто копируете в принципе неплохие практики продвигаемые Micrium-ом и другими.

Но это еще приемлемо для небольших проектов в пару десятков файлов.
А если в проекте счет файлам идет на сотни (а это средненький дивайс с GUI, FS, TCP, RTOS ), то этот подход не работает.

Представьте себе main.h с этаким списком в несколько сот заголовочных файлов. Только взглянув на такой поплохеет.
Управлять таким и разруливать взаимозависимости просто катастрофа.
Проект обязательно надо преобразовать в иерархическую структуру.

Поэтому если хотите делать серьезные проекты сразу думайте над иерархией.
Иерархия это например: плата (BSP), платформа (PSP), архитектура/драйвера, приложение.
Также стоит сразу думать о реюзинге. Отсюда может следовать, что не стоит располагать все глобальные переменные в одном файле.
Потом стоит подумать о многозадачности, это может потребовать как можно больше глобальных переменных скомпоновать в структуры чтобы превратить их потом в динамически создаваемые.
И т.д.
Что касается разбивки на файлы, то могу назвать пару критериев.
Как только размер файла подошел к 50 Кб, то его надо как-то разбить, а то время скролинга исходников начинает неявно доминировать в процессе разработки.
Если планируется реюзинг каких-то модулей, то эти модули разделяются на файлы зависимые и независимые от платформы.
Опять же реюзинг заставляет изобретать уровни абстракции, это тоже порождает файлы.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 15:10
Сообщение #11


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AlexandrY @ Mar 23 2014, 17:43) *
Представьте себе main.h с этаким списком в несколько сот заголовочных файлов. Только взглянув на такой поплохеет.
Управлять таким и разруливать взаимозависимости просто катастрофа.

Смотрю на примеры с USB, и не въезжаю, что какие файлы делают. Вот их там пара десятков и есть, но не запомнить, где что искать. Много мелких файлов запутывают.
С другой стороны, файлы своих исходников есть и больше 150 KB. Да, искать напрягает, Notepad++ пыхтит вместе со мной, зато знаю, что оно где-то там. rolleyes.gif
Количество файлов как раз под два десятка подбирается. И в них есть и GUI, и RTOS, и DSP. А еще надо и USB, FS...
Пока держу все в одном каталоге. Но Keil уже сам создает несколько папок с исходниками в проекте.
И еще хочется как-то уровнять файлы по размеру, тоже ищу логику, как делить.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Mar 23 2014, 15:56
Сообщение #12


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(ViKo @ Mar 23 2014, 17:10) *
Да, искать напрягает, Notepad++ пыхтит вместе со мной, зато знаю, что оно где-то там. rolleyes.gif


Ну так с этого и надо было начинать. Кто же в Notepad-е делает серьезные проекты.
Брать надо SlickEdit или на худой конец Eclipse со специальными add-on-ами.

А так конечно упретесь. Ни нормального броузинга исходников, ни рефакторинга. Тут хоть где объявляйте хидеры. Легче не станет.
Да еще все в одной директории.
Память не резиновая, не надо ее напрасно тренировать поиском по линейным спискам.
Используйте более гибкие иерархические структуры и деревья. Память их лучше обрабатывает.

Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2014, 16:18
Сообщение #13


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AlexandrY @ Mar 23 2014, 18:56) *
Ну так с этого и надо было начинать. Кто же в Notepad-е делает серьезные проекты.
Брать надо SlickEdit или на худой конец Eclipse со специальными add-on-ами.

SlickEdit не пользовался, в Notepad++ найдется все, что нужно, я думаю. И плагины у него тоже есть.
Вопрос не в редакторе, а в голове.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Mar 23 2014, 16:41
Сообщение #14


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(ViKo @ Mar 23 2014, 18:18) *
SlickEdit не пользовался, в Notepad++ найдется все, что нужно, я думаю. И плагины у него тоже есть.
Вопрос не в редакторе, а в голове.


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

Меня всегда удивляло, что новые языки изобретают не психологи, а гики от программирования.
Потом я понял, что все эти новые синтаксисы это только способ размежевания и борьбы программистов между собой.
А настоящий прогресс несут редакторы и библиотеки.
Go to the top of the page
 
+Quote Post
AnatolyT
сообщение Mar 23 2014, 16:47
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 29-03-10
Пользователь №: 56 269



Так как до сих пор не делал крупные проекты, типичный проект состоит максимум из 10-15 исходных модулей, стараюсь использовать стандартный подход, к каждому исходнику свой хедер с описанием функций. Все определения типов и свои дефайны определяю в отдельном хедере. Глобальные переменные определяю по мере создания в каждом исходном модуле, потом их легче будет найти по смыслу, использую венгерскую нотацию или скорее похожую на нее. Не определяю крупные массивы для обработки данных, аллокация в хипе в начале каждой обработки, передача через указатель по всей глубине обработки, после обработки освобождаю массив. Стараюсь передавать результат через указатель в формальных параметрах, возврат каждой функции обработки это тип ошибки по всей глубине обработки или 0 если корректное выполнение. Стараюсь не перегружать main.c, только определение прерываний, установка начальных режимов аппаратных модулей и глобальный вызов.
Go to the top of the page
 
+Quote Post
halfdoom
сообщение Mar 24 2014, 01:59
Сообщение #16


Профессионал
*****

Группа: Свой
Сообщений: 1 003
Регистрация: 20-01-05
Пользователь №: 2 072



Цитата(ViKo @ Mar 23 2014, 09:57) *
Не слишком ли я запутываю свои проекты? Например, гложет мысль, как правильнее - использовать display.h в main.h или в display.c?


Собирательство всех заголовков в один, не самая хорошая идея. В сообществе разработчиков ОС FreeBSD, есть такой уважаемый человек, как Bruce Evans. Он весьма ревниво следит за стилевой организацией системных .h файлов, да и другого кода. Некоторые из его требований могут показаться надуманными, но если почитать разъяснения, то все становится на свои места. Рекомендую прочесть документ http://www.freebsd.org/cgi/man.cgi?query=style&sektion=9 - в нем много полезных советов.
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Mar 24 2014, 02:24
Сообщение #17


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(ViKo @ Mar 23 2014, 10:57) *
...чтобы не включать всю кучу h-файлов во все c-файлы, собрал их в одну кучу в main.h....


у компиляторов порой встречается глюк - не чуствительность к изменениям ашника в ашнике.
ну это так...к слову..

а если по теме:
в общий ашник скидывают то, что точно не будет правиться. Ну например файлы объявлений стандартной библиотеки.
Или скажем внешней библиотеки третьих лиц.
Например если взять любой пример от ST то заголовочные файлы включаются в один общий.
Только не забывайте что код в ввиде библиотеки педоставленsm.gif

по поводу консерватории - где и как объявлять глобальные переменные. Так это же вопрос консерватории а не инструмента. Пишите Вы хоть
на си или си плас плас или джаве - фиолетов, это вторично(язык описания). первично логика - кто и как должен видеть, иметь доступ,
править, читать, атомарность доступа, шаринг, время жизни и т.д... аспектов много...
Например:
взять те же самые библиотеки. Удобно писать экспорт-импорт внутри одного ашника. И в зависимости от условия компиляции
объявлять везде что это внешняя переменная либо своя(если внутри либы). При этом объявление носит уникальность записи и исключает двойную
или более трактовку.
Go to the top of the page
 
+Quote Post
dxp
сообщение Mar 24 2014, 02:47
Сообщение #18


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



QUOTE (ViKo @ Mar 23 2014, 17:49) *
А с-файл как называете - main.cpp или по имени проекта? Тоже колеблюсь туда-сюда. Main найти проще, но смысла меньше.
Помню, за имя Top_m в SV модератор по ПЛИСам намекнул, что отгрыз бы своему "падавану" руки. w00t.gif

Не, main.cpp присутствует, тут никаких дилемм нет - в нём живёт как правило только функция main(), которая запускает прикладной код. Маленький файл. А заголовок - он содержит проектно-зависимое содержание, поэтому по имени проекта и зовётся.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AnatolyT
сообщение Mar 24 2014, 02:54
Сообщение #19


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 29-03-10
Пользователь №: 56 269



Хотел бы добавить к своему сообщению здесь, ничего необычного, но может кому-нибудь будет интересно. Деление проекта на модули разное, но всегда чисто смысловое, по обслуживанию аппаратных модулей, по применяемым алгоритмам обработки, по элементам пользовательского интерфейса и т.п. Размеры модулей разные и думаю что это большого значения не имеет, от 200 строк кода или меньше до 1000-1500 строк, включая необходимые комментарии. В среднем 300-400 строк в модуле. При этом легко можно использовать какой-либо модуль без существенной переделки в других проектах, некоторая унификация)). При желании можно оформить в виде библиотеки. Архив своих проектов также полезен, чтобы не изобретать велосипед заново, было такое что решение для аналогичной задачи нашел на пятидюймовой дискете в своих проектах более чем 10-летней давности.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Mar 24 2014, 05:21
Сообщение #20


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(ViKo @ Mar 23 2014, 19:18) *
SlickEdit не пользовался, в Notepad++ найдется все, что нужно, я думаю. И плагины у него тоже есть.
Вопрос не в редакторе, а в голове.

Попробуйте Geany. Лучше нотепадов однозначно.
Вкратце.
Проект в geany - это просто набор открытых файлов. Для маленького проекта никаких дополнительных телодвижений не нужно - TAGS и автодополнения работают автоматом.
Если кол-во файлов такое, что заметны тормоза - делается tags-файл на используемые либы и продолжаете в том же духе.
Но эклипс все равно круче.

Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 24 2014, 05:47
Сообщение #21


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(_Pasha @ Mar 24 2014, 08:21) *
Попробуйте Geany. Лучше нотепадов однозначно.
...
Но эклипс все равно круче.

Это всё инструменты.
В Notepad++ я открываю в двух областях разные файлы и копирую, то, что надо, из одного файла в другой. Вот и вся reusability.
Или один и тот же файл редактирую в разных местах. Очень удобно.
halfdoom дал ссылку, там больше про стиль оформления. Многое из того я использую, кое с чем не согласен.

Повторюсь, впадаю в панику, когда вижу 20 файлов, посвященных USB. Это нужно взять лист ватмана, и попытаться на нем нарисовать все связи между элементами. В меньшей степени это относится и ко всем другим библиотечным функциям.
P.S. А как сделать проще для USB - не знаю!
Go to the top of the page
 
+Quote Post
halfdoom
сообщение Mar 24 2014, 07:02
Сообщение #22


Профессионал
*****

Группа: Свой
Сообщений: 1 003
Регистрация: 20-01-05
Пользователь №: 2 072



Цитата(ViKo @ Mar 24 2014, 08:47) *
halfdoom дал ссылку, там больше про стиль оформления. Многое из того я использую, кое с чем не согласен.


Полезно, так-же, заглянуть в код этой ОС:

CODE

#include <sys/stdint.h>
#include <sys/stddef.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include "usbdevs.h"

#include <dev/usb/usb_debug.h>
#include <dev/usb/usb_process.h>

#include <dev/usb/serial/usb_serial.h>
#include <dev/usb/serial/uftdi_reg.h>


Цитата(ViKo @ Mar 24 2014, 08:47) *
Повторюсь, впадаю в панику, когда вижу 20 файлов, посвященных USB.


Для сложного девайса ничего страшного. Если эти файлы разбиты по функционалу, то ориентироваться в них несложно. Иногда бывает другая крайность - когда задачу дробят на слишком мелкие кусочки, в ущерб общей логике. Тогда конечно, крайне сложно запомнить где что лежит.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 1 2014, 11:36
Сообщение #23


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(ViKo @ Mar 24 2014, 08:47) *
Это всё инструменты.
В Notepad++ я открываю в двух областях разные файлы и копирую, то, что надо, из одного файла в другой. Вот и вся reusability.
Или один и тот же файл редактирую в разных местах. Очень удобно.

Только что "открыл", что Notepad++ может выдать список функций в файле! И даже отсортировать их по алфавиту, если хочется. Красота.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th July 2025 - 23:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01646 секунд с 7
ELECTRONIX ©2004-2016