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

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Заголовочные файлы и модули., Как правильно?
Baser
сообщение Jan 1 2018, 18:47
Сообщение #16


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(Smoky @ Jan 1 2018, 07:55) *
Разобрав несколько примеров сделал попытку переделать один из своих проектов, разделив свои заголовочные файлы на .c и .h. Как только я это сделал с одним файлом компилятор сразу же "потерял" функции в других заголовочных файлах, которые я не изменял.

Переделка только одного файла может только запутать все эти перекрестные ссылки.
Нужно переделывать все. Обычно это довольно трудоемко.
У меня есть опыт перенятия чужих проектов начинающих программистов, которые плохо понимали структуризацию проектов на Си.
На "распутывание" проекта из ~20 файлов уходила пара дней sad.gif
Там еще будут проблемы грамотного ограничения области видимости переменных и функций,
но это вам можно оставить на потом, после вникания в это.

Цитата(Smoky @ Jan 1 2018, 16:54) *
Логику использования .h файлов я понял, я не уловил в примерах закономерности директив #include в модулях .c

Для начала, все .с файлы должны быть включены в проект в самой IDE AVRStudio
Там должно быть окно с деревом файлов проекта. Файлы обычно включаются командой типа: Add file to project

С инклудами .h файлов все просто. Запускаете компиляцию проекта. Например на файл main.c компилятор ругается, что не может найти функцию func(). Вы поиском находите, что эта функция у вас находится в файле uart.c, а в файле uart.h есть описание её прототипа. Значит, в начало файла main.c нужно добавить #include uart.h
И так по всем ошибкам компилятора.

С Новым Годом! santa2.gif
Go to the top of the page
 
+Quote Post
Smoky
сообщение Jan 1 2018, 19:40
Сообщение #17


Местный
***

Группа: Свой
Сообщений: 401
Регистрация: 7-05-10
Из: Оренбург
Пользователь №: 57 135



Цитата(Baser @ Jan 2 2018, 00:47) *
Переделка только одного файла может только запутать все эти перекрестные ссылки.
Нужно переделывать все. Обычно это довольно трудоемко.


Согласен. Поэтому решил начать сначала. Прошу посмотреть фрагмент программы и сказать что я делаю не так. Этот фрагмент инициализирует LCD 1х20, загружает пользовательские символы, выводит на LCD "Инициализация" и короткий звуковой сигнал 10 мсек. Файлы .c компилируются нормально но вот сборка не получается. Директивы #include вставлял по мере вывода сообщений об ошибках но результата так и не получил...
Прикрепленные файлы
Прикрепленный файл  Cloc_Meteo1_2.zip ( 23.49 килобайт ) Кол-во скачиваний: 12
 


--------------------
Лень, оттвори дверь, сгоришь - а хоть и сгорю, но не оттворю.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Jan 1 2018, 20:01
Сообщение #18


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Мне пришлось импортировать проект в AS 7
Я правильно понимаю, что вы получаете вот такие ошибки?
Код
Severity    Code    Description    Project    File    Line
Error        ld returned 1 exit status    Cloc_Meteo1_2    collect2.exe    0
Error        recipe for target 'Cloc_Meteo1_2.elf' failed    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\default\Makefile    129
Error        multiple definition of `Smil_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `sign_clcdur'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Pikout.c    30
Error        multiple definition of `Sand_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Pres_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Line_message'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\default\Symbol.o    1
Error        multiple definition of `insg'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\default\Pikout.o    1
Error        multiple definition of `Humi_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Hood_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Home_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Grad_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10
Error        multiple definition of `Bell_char'    Cloc_Meteo1_2    D:\Poligon\Cloc_Meteo1_2\Symbol.c    10


Пройдемся по ошибке
Sand_char

Делаем поиск по проекту, видим, что в файле Symbol.h определено следующее:
Код
const byte Sand_char[] PROGMEM={0,27,0,4,0,14,17,0}; //Загружаемый символ грусти


Ищем какие файлы инклюдят этот Symbol.h

#include "Symbol.h" имеется в Base.c и в Symbol.c

Вы же помните да, что #include тупо добавляет текст из .h файла в .c файл?
Вот мы и имеем ситуацию, когда в двух единицах трансляции(.с файлах) определена ГЛОБАЛЬНАЯ переменная const byte Sand_char[]

Тоесть на выходе будут два .obj файла с такой перменной с двумя разными адресами в памяти.
Линкер хочет при упоминании Sand_char найти адрес и подставить, но не может т.к. есть два кандидата с одинаковыми именами.

И такая ситуация у вас там похоже по всем ошибкам. Как только вы поймете их природу и всё то, что я вам описал по поводу процесса сборки проекта - сможете пофиксить.

Ситуацию с Sand_char можно разрулить несколькими способами:
1. добавить static
Код
static const byte Sand_char[] PROGMEM={0,27,0,4,0,14,17,0}; //Загружаемый символ грусти

Таким образом каждый .c файл себе заинклюдит этот .h файл и получит статик, область видимости которого ограничена одной единицей трансляции(т.е. только этим компилируемым .с файлом).
2. У вас уже есть файл Symbol.c. Отлично!
Перемещаем вот это
Код
const byte Sand_char[] PROGMEM={0,27,0,4,0,14,17,0}; //Загружаемый символ грусти
в Symbol.c
А в Symbol.h пишем
Код
extern const byte Sand_char[];
Я сейчас сходу не уверен как это скомпилится, возможно надо будет по-танцевать с прогмэмом, но смысл этого всего в следующем:
Переменная глобальная переменная Sand_char будет экспортирована только из одного .obj файла(Symbol.obj) а все остальный .c файлы которые сделают #include "Symbol.h" - получат представление о том, что есть такая переменная описанная так-то, но сама эта переменная определена где-то в другом модуле(слово extern). Таким образом у линкера будет только одна копия Sand_char и он сможет подставить ее адрес везде где она используется.

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


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
ArtemKAD
сообщение Jan 1 2018, 20:10
Сообщение #19


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

Группа: Свой
Сообщений: 1 508
Регистрация: 26-06-06
Из: Киев
Пользователь №: 18 364



В хидеры включены переменные(и константные переменные в т.ч.), что ошибочно. Всем объявлениям(но не extern-прототипам) переменных, а тем более объявлениям которые используются исключительно в пределах одного файла место только в .с-файле. Если есть желание какую либо переменную сделать глобальной(использовать в нескольких файлах), её прототип в .h-файле надо объявить как extern . Если глобальной хочется сделать структуру, в .h-файле объявляется её typedef, там-же объявляется прототип переменной через extern, а сама переменная структуры и её инициализация объявляется уже в .с-файле.

ЗЫ. Кстати, PROGMEM это макрос указывающий атрибут переменной поэтому как по мне лучше его объявить до имени переменной.
const byte PROGMEM Home_char[] ={4,10,17,31,21,17,31,0}; //Загружаемый символ домика
или даже так:
PROGMEM const byte Home_char[] ={4,10,17,31,21,17,31,0}; //Загружаемый символ домика
Тогда меньше непоняток в написанном возникает.
Go to the top of the page
 
+Quote Post
Baser
сообщение Jan 1 2018, 20:30
Сообщение #20


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(Smoky @ Jan 1 2018, 21:40) *
Прошу посмотреть фрагмент программы и сказать что я делаю не так.

Студии у меня нет, посмотрел глазами.
С функциями уже хорошо.
Но переменные объявляете не правильно.

1) Все объявления переменных, по которым компилятор выделяет память, должны находится в начале .c файлов.
В .h файлах помещаются только разные макросы и определения.

То есть, всякие:
volatile word sign_clcdur=0;
двигаем в .c файл.

Если эта переменная используется только в нем, больше ничего не нужно.
Если она применяется еще в других файлах, тогда в соответствующий .h добавляется:
extern volatile word sign_clcdur;

И этот .h файл включается через #include туда, где применяется.

2) Структуры объявляются через typedef в .h файлах

typedef volatile struct //Структура индексов
{
bit level:1; //Индекс текущего уровня звукового порта
bit waiting:1; //Индекс ожидания готовности к формированию звукового сигнала
} insg_t;

extern insg_t insg;

Само определение структуры, по которому выделяется память и проводится инициализация, в .c файле:
insg_t insg = {0,0};

3) Порядок нескольких #include имеет значение, т.к. компилятор работает последовательно,
он не знает определений, которые будут "ниже", "позже".
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Jan 1 2018, 21:10
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(sigmaN @ Jan 1 2018, 23:01) *
...
Ситуацию с Sand_char можно разрулить несколькими способами:
1. добавить static
...

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


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Jan 1 2018, 21:24
Сообщение #22


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Цитата
Первый способ создаст две переменных, ошибок не будет, но программ не будет работать.
Нет, в данном конкретном проекте это не станет проблемой.
НО так как этот static способ не совсем правильный я внизу своего сообщения добавил:
Цитата
Второй способ мне в данном случае нравится больше и кажется более корректным.


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Smoky
сообщение Jan 2 2018, 17:11
Сообщение #23


Местный
***

Группа: Свой
Сообщений: 401
Регистрация: 7-05-10
Из: Оренбург
Пользователь №: 57 135



Цитата(Baser @ Jan 2 2018, 02:30) *
Студии у меня нет, посмотрел глазами.
С функциями уже хорошо.
Но переменные объявляете не правильно.

1) Все объявления переменных, по которым компилятор выделяет память, должны находится в начале .c файлов.
В .h файлах помещаются только разные макросы и определения.


Коллеги, вы "ломаете" все мои установки! Программировать начал с 2009 г. , оказалось что это лишь мои "вершки". Попробую всё сначала, спасибо за ценные советы. Предлагаю для анализа файл сообщений который выводит компилятор AVRStudio.
Прикрепленные файлы
Прикрепленный файл  OutCloc_Meteo1_2.zip ( 5.28 килобайт ) Кол-во скачиваний: 8
 


--------------------
Лень, оттвори дверь, сгоришь - а хоть и сгорю, но не оттворю.
Go to the top of the page
 
+Quote Post
Baser
сообщение Jan 2 2018, 19:18
Сообщение #24


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(Smoky @ Jan 2 2018, 19:11) *
Предлагаю для анализа файл сообщений который выводит компилятор AVRStudio.

Коряво как-то Студия лог сборки выводит, ну да и ладно.
Там у вас все время мелькает : "multiple definition of ..."

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

Сверьтесь с моими рекомендациями выше.

Для лучшего понимания подсказка:
Определения, по которым НЕ выделяется память, и которые могут быть в .h файлах:

#define
enum
typedef
extern
прототипы функций - типа void func(void);

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

з.ы. еще может быть переопределение одних и тех же #define в разных местах, тоже будет ругаться.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Jan 2 2018, 21:30
Сообщение #25


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Цитата
Коллеги, вы "ломаете" все мои установки! Программировать начал с 2009 г
А разницы нет с какого года. При правильно подходе я думаю и за год можно знать и применять 98% всех свойств языка Си.
В сравнении с С++ там вообще всё просто.
Предполагаю, что не с того вы начали... Просто видимо набрали пару примеров, сформировали у себя какие-то представления и решали поставленные задачи исходя из этого представления. Без особого понимания что к чему.
Вам бы начать изучение как положено с книжечек по языку. А так то и стандарт языка полистать было бы очень неплохо(но это уже на более поздних этапах будет уместно).

Не думаю, что по Си придумали что-то лучшее чем сами авторы языка(за качество перевода не отсечаю, просто нагуглил)
http://www.nsu.ru/xmlui/bitstream/handle/nsu/9058/kr.pdf

В понимании процесса сборки вам надо бы полистать документацию компилятора и линкера.
Непонятные слова и выражения тут-же гуглить и пополнять свои знания.
Ну может быть начните с документации GCC, я не знаю...
https://gcc.gnu.org/onlinedocs/
А может и что-то более удобоваримое можно нагуглить.. В любом случае вам нужно начинать с основ.


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Smoky
сообщение Jan 3 2018, 08:00
Сообщение #26


Местный
***

Группа: Свой
Сообщений: 401
Регистрация: 7-05-10
Из: Оренбург
Пользователь №: 57 135



Цитата(sigmaN @ Jan 3 2018, 03:30) *
Вам бы начать изучение как положено с книжечек по языку. А так то и стандарт языка полистать было бы очень неплохо(но это уже на более поздних этапах будет уместно).


Да вы правы, как я уже говорил, всё придётся повторить сначала... Я и начал в 2009 году с изучения "С за 21 ден" Брэдли Л.Джонса и Питера Эйткена. Но моя беда в том что все примеры в этой книге основаны на одном файле .c и stdio.h. Поэтому, я думаю, понятно, почему я всё это время тоже использовал один файл .c и "кучу" заголовочных файлов. Всем спасибо за ценные советы и ссылки. Далее я попробую сам...


--------------------
Лень, оттвори дверь, сгоришь - а хоть и сгорю, но не оттворю.
Go to the top of the page
 
+Quote Post
Владивольт
сообщение Jan 3 2018, 17:39
Сообщение #27


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

Группа: Участник
Сообщений: 168
Регистрация: 14-02-10
Пользователь №: 55 490



похожая тема - взгляните


--------------------
#define TRUE (4==(2*2))
Go to the top of the page
 
+Quote Post
Smoky
сообщение Jan 10 2018, 17:06
Сообщение #28


Местный
***

Группа: Свой
Сообщений: 401
Регистрация: 7-05-10
Из: Оренбург
Пользователь №: 57 135



Моя благодарность "волхвам" за науку, всё получилось так как нужно. Ещё раз примите моё спасибо и пожелания удачи. biggrin.gif


--------------------
Лень, оттвори дверь, сгоришь - а хоть и сгорю, но не оттворю.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Jan 10 2018, 18:44
Сообщение #29


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Обращайтесь, я по умничать всегда рад wink.gif


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Unfog
сообщение Jan 12 2018, 06:13
Сообщение #30


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 20-05-12
Из: Санкт-Петербург
Пользователь №: 71 932



Для исключения повторной компиляции содержимого h-файла несколько раз еще можно использовать следующие приемы:

Код
#ifndef DEFINE_H_
#define DEFINE_H_

int i = 0;

#endif /*DEFINE_H_*/

или
Код
#pragma once
Go to the top of the page
 
+Quote Post

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

 


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


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