Baser 5 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба Разобрав несколько примеров сделал попытку переделать один из своих проектов, разделив свои заголовочные файлы на .c и .h. Как только я это сделал с одним файлом компилятор сразу же "потерял" функции в других заголовочных файлах, которые я не изменял. Переделка только одного файла может только запутать все эти перекрестные ссылки. Нужно переделывать все. Обычно это довольно трудоемко. У меня есть опыт перенятия чужих проектов начинающих программистов, которые плохо понимали структуризацию проектов на Си. На "распутывание" проекта из ~20 файлов уходила пара дней :( Там еще будут проблемы грамотного ограничения области видимости переменных и функций, но это вам можно оставить на потом, после вникания в это. Логику использования .h файлов я понял, я не уловил в примерах закономерности директив #include в модулях .c Для начала, все .с файлы должны быть включены в проект в самой IDE AVRStudio Там должно быть окно с деревом файлов проекта. Файлы обычно включаются командой типа: Add file to project С инклудами .h файлов все просто. Запускаете компиляцию проекта. Например на файл main.c компилятор ругается, что не может найти функцию func(). Вы поиском находите, что эта функция у вас находится в файле uart.c, а в файле uart.h есть описание её прототипа. Значит, в начало файла main.c нужно добавить #include uart.h И так по всем ошибкам компилятора. С Новым Годом! :santa2: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба Переделка только одного файла может только запутать все эти перекрестные ссылки. Нужно переделывать все. Обычно это довольно трудоемко. Согласен. Поэтому решил начать сначала. Прошу посмотреть фрагмент программы и сказать что я делаю не так. Этот фрагмент инициализирует LCD 1х20, загружает пользовательские символы, выводит на LCD "Инициализация" и короткий звуковой сигнал 10 мсек. Файлы .c компилируются нормально но вот сборка не получается. Директивы #include вставлял по мере вывода сообщений об ошибках но результата так и не получил... Cloc_Meteo1_2.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба Мне пришлось импортировать проект в 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 и он сможет подставить ее адрес везде где она используется. Второй способ мне в данном случае нравится больше и кажется более корректным. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
artemkad 55 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба В хидеры включены переменные(и константные переменные в т.ч.), что ошибочно. Всем объявлениям(но не 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}; //Загружаемый символ домика Тогда меньше непоняток в написанном возникает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба Прошу посмотреть фрагмент программы и сказать что я делаю не так. Студии у меня нет, посмотрел глазами. С функциями уже хорошо. Но переменные объявляете не правильно. 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 имеет значение, т.к. компилятор работает последовательно, он не знает определений, которые будут "ниже", "позже". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба ... Ситуацию с Sand_char можно разрулить несколькими способами: 1. добавить static ... Так можно ошибки разрулить, а ситуацию только усугубить. Наверняка автор предусматривал, что это одна и та же переменная. Первый способ создаст две переменных, ошибок не будет, но программ не будет работать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 1 января, 2018 Опубликовано 1 января, 2018 · Жалоба Первый способ создаст две переменных, ошибок не будет, но программ не будет работать. Нет, в данном конкретном проекте это не станет проблемой. НО так как этот static способ не совсем правильный я внизу своего сообщения добавил: Второй способ мне в данном случае нравится больше и кажется более корректным. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 2 января, 2018 Опубликовано 2 января, 2018 · Жалоба Студии у меня нет, посмотрел глазами. С функциями уже хорошо. Но переменные объявляете не правильно. 1) Все объявления переменных, по которым компилятор выделяет память, должны находится в начале .c файлов. В .h файлах помещаются только разные макросы и определения. Коллеги, вы "ломаете" все мои установки! Программировать начал с 2009 г. , оказалось что это лишь мои "вершки". Попробую всё сначала, спасибо за ценные советы. Предлагаю для анализа файл сообщений который выводит компилятор AVRStudio. OutCloc_Meteo1_2.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 2 января, 2018 Опубликовано 2 января, 2018 · Жалоба Предлагаю для анализа файл сообщений который выводит компилятор AVRStudio. Коряво как-то Студия лог сборки выводит, ну да и ладно. Там у вас все время мелькает : "multiple definition of ..." Это говорит о том, что у вас есть дубликаты определений переменных, по которым выделяется память, находящиеся в разных файлах. Сверьтесь с моими рекомендациями выше. Для лучшего понимания подсказка: Определения, по которым НЕ выделяется память, и которые могут быть в .h файлах: #define enum typedef extern прототипы функций - типа void func(void); все остальное - в .c файлы .c файлы пока друг в друга через #include не включайте (это можно, но нужно понимать, что вы делаете). з.ы. еще может быть переопределение одних и тех же #define в разных местах, тоже будет ругаться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 2 января, 2018 Опубликовано 2 января, 2018 · Жалоба Коллеги, вы "ломаете" все мои установки! Программировать начал с 2009 г А разницы нет с какого года. При правильно подходе я думаю и за год можно знать и применять 98% всех свойств языка Си. В сравнении с С++ там вообще всё просто. Предполагаю, что не с того вы начали... Просто видимо набрали пару примеров, сформировали у себя какие-то представления и решали поставленные задачи исходя из этого представления. Без особого понимания что к чему. Вам бы начать изучение как положено с книжечек по языку. А так то и стандарт языка полистать было бы очень неплохо(но это уже на более поздних этапах будет уместно). Не думаю, что по Си придумали что-то лучшее чем сами авторы языка(за качество перевода не отсечаю, просто нагуглил) http://www.nsu.ru/xmlui/bitstream/handle/nsu/9058/kr.pdf В понимании процесса сборки вам надо бы полистать документацию компилятора и линкера. Непонятные слова и выражения тут-же гуглить и пополнять свои знания. Ну может быть начните с документации GCC, я не знаю... https://gcc.gnu.org/onlinedocs/ А может и что-то более удобоваримое можно нагуглить.. В любом случае вам нужно начинать с основ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 3 января, 2018 Опубликовано 3 января, 2018 · Жалоба Вам бы начать изучение как положено с книжечек по языку. А так то и стандарт языка полистать было бы очень неплохо(но это уже на более поздних этапах будет уместно). Да вы правы, как я уже говорил, всё придётся повторить сначала... Я и начал в 2009 году с изучения "С за 21 ден" Брэдли Л.Джонса и Питера Эйткена. Но моя беда в том что все примеры в этой книге основаны на одном файле .c и stdio.h. Поэтому, я думаю, понятно, почему я всё это время тоже использовал один файл .c и "кучу" заголовочных файлов. Всем спасибо за ценные советы и ссылки. Далее я попробую сам... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vladivolt 0 3 января, 2018 Опубликовано 3 января, 2018 · Жалоба похожая тема - взгляните Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 10 января, 2018 Опубликовано 10 января, 2018 · Жалоба Моя благодарность "волхвам" за науку, всё получилось так как нужно. Ещё раз примите моё спасибо и пожелания удачи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 10 января, 2018 Опубликовано 10 января, 2018 · Жалоба Обращайтесь, я по умничать всегда рад ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Unfog 0 12 января, 2018 Опубликовано 12 января, 2018 · Жалоба Для исключения повторной компиляции содержимого h-файла несколько раз еще можно использовать следующие приемы: #ifndef DEFINE_H_ #define DEFINE_H_ int i = 0; #endif /*DEFINE_H_*/ или #pragma once Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться