Как оптимально разделять код (методология создание слождного проекта)?
- Войдите на сайт для отправки комментариев
Я не спец в Си.
Прекрасно понимаю, как все части проекта побить на классы, для каждого из которых сделать <класс>.h и <класс>.cpp (например eeprom.h и eeprom.cpp, nrf.h и nrf.cpp).
Но, сильно смущает скорость исполнения кода, в котором все функции вызываются через указатели на классы.
Допустим, отказываюсь от классов. Какова альтернатива?
Могу переменные, относящиеся ранее к классу, поместить в struct <класс> {..} и эта структура описывается в <класс>.h, а ее экземпляр объявляется в скетче.
Но вот с функциями то как быть?
Могу их разнести по .cpp файлам.Однако при #include <..>.cpp arduino IDE их не находит.
Может кто посоветует как разбить сложный проект на части без использования классов?
Или пошлите меня куда .. по ссылке.
Благодарю
Тож интересует. Либа для часов 1307 жжёт напалмом, со своими запросами к оперативе.
Еще, например, в <...>.h
В <...>.cpp
Понятно, что компилятор ругается, ведь нет понятия global переменной.
Чего-то я туплю.
Может ее переименовать и удалить все ненужные процедуры и тп?
ругается потому, что название функции совпадает с названием типа int
Нет, это я пример неправильно описал. Пусть rr_int.
Ругается так:
И так на каждую переменную, объявленную в .h и используемую в rr_int.
То есть, насколько я понимаю, компилятор считает, что переменная rr в функции и переменная rr в .h - не одно и то же.
Как его заставить поверить, не используя классы?
Передавать переменные в функцию тоже не могу. Их бывает много. Накладно.
Меня бы устроил совершенно тупой метод склеивания скетча из тучи разных файлов.
Такое чудо есть на Си?
С .h и .cpp файлами уже два часа бьюсь - безрезультатно.
Все это нужно для того, чтобы части проекта использовались на разных arduino.
Т.е. хочется, изменив один файл, получить изменения сразу для всех частей проекта при сборке.
Ура, получилось:
Просто делаю
И, таким образом, получаю скетч, склеенный из множества cpp файлов, каждый из которых вмещает глобальные переменные и функции для отдельной части проекта.
Всем спасибо.
Последнее, никак не получается путь вынести в #define, чтобы при смене пути не заменять везде путь.
не работает
osetroff, я бы не стал сильно беспокоиться насчёт снижения скорости из-за использования классов. В "серьёзных" процессорах скорость почти не снижается, а в некоторых случаях даже увеличивается, при правильно написанном коде.
Ардуиновские AVR-контроллеры, может быть, не так хорошо заточены под классы, но поверьте, в ардуине есть много мест, которые снижают эффективность намного больше.
По поводу ошибки "multiple definition of ..." - надо просто один раз чётко понять, для чего принято использовать файлы .c или .cpp, и для чего .h
После этого всё станет легко и просто. :)
В .h файлы не принято помещать код, создающий какие-нибудь объекты - переменные, функции, структуры - что угодно. Но зато можно, и нужно, описывать эти объекты. То есть, компилятору просто сообщается, что есть какой-то тип объекта, что мы будем, может быть, с ним работать, но создавать объект этого типа пока не надо.
Вы в своём коде именно создали функцию rr_int в .h-файле.
Сравните:
это объявление. Компилятору сказали, что функция rr_int существует, что она возвращает значение int, и что параметров у неё нет. Такое объявление можно распихивать в любом месте Вашего кода, сколько угодно раз. Ошибки это не вызовет, и размер скомпилённого файла не увеличит.
а это уже описание. Компилятор должен перевести эти строчки на "машинный язык", и запихнуть их в генерируемый файл. Если Вы разместили такое описание в .h-файле, а потом включили этот файл в несколько .cpp-файлов, компилятор (а точнее линкер) попытается поместить эту функцию в выходной файл несколько раз. Этого делать бессмысленно, и поэтому запрещено - вот Вам и выдаётся соответствующая ошибка.
Ура, получилось:
Просто делаю
И, таким образом, получаю скетч, склеенный из множества cpp файлов, каждый из которых вмещает глобальные переменные и функции для отдельной части проекта.
Оужос! Для чего я всё это писал? :)
Ладно, можно и так конечно. Но это неправильно. То есть правильно, но криво - а значит не правильно.
Благодарю. Ясно.
А как из #define путь в #include прописать , не подскажете?
P.S.Почему не правильно, если работает, как нужно?
Мои цели:
1)отказаться от классов;
2)структурировать код;
3)сделать подобие библиотек;
достигнуты.
Это же для микроконтроллера пишется, приходится экономить.
Вот у меня, к примеру 490us подается питание на катушку соленоидного клапана, 1000us-490us не подается.
Скорость важна.
Или, например, для радиосети мне проще буфер сделать фиксированной длины 32x20=640байт, а оперативки-то тоже не так много.
Тож интересует. Либа для часов 1307 жжёт напалмом, со своими запросами к оперативе.
Используйте либу для 3231
А как из #define путь в #include прописать , не подскажете?
Тысячи извинений - но не подскажу. Обычно, дополнительные пути поиска для #include задаются не в самих файлах, а в опциях компилятора. Но как к этим опциям добраться в ардуине не знаю, может ещё кто-то подскажет. Вообще, гугл говорит, что опции можно менять в ардуиновском файле "Documents and Settings\<user_name>\Application Data\Arduino\preferences.txt".
Для gcc-компилятора вроде должна помочь опция -Iнаш_global_path. Я попробовал, но ничего не получилось.
Опять же, буду благодарен если кто-то подскажет. Иногда поменять какие-то ключи компилятора очень даже хочется.
P.S.Почему не правильно, если работает, как нужно?
Ну, может и погорячился немного, или не понял что-то. Если ваша цель - удобно разместить файлы по каталогам, и использовать некоторые в разных ардуинопроектах - то да, действительно так быстро ничего придумать не получается.
Но если все файлы в одном каталоге, как у этой ардуины принято - смысла включать .cpp-файлы один в другой не вижу. Они же и так все "склеиваются".
А экономить, и место и время - тут я согласен, я тоже всегда за это. Только в ардуиносреде у меня это плохо получается. Теряюсь я в ней, как-то тут всё бесконтрольно - что сама хочет, то и творит. Я так не привык. :)
сильно смущает скорость исполнения кода, в котором все функции вызываются через указатели на классы
И уж ещё, в защиту классов. :)
Функции не вызываются через указатели. Во всяком случае, пока вы не используете виртуальные функции.
Через указатели передаются "классовые" данные для этих функций. Но я бы не сказал, что скорость обращения к этим данным ниже, например, по сравнению с глобальными. Несколько тактов, правда, тратится на установку самих этих указателей - но думаю не много.
А ещё, можно создавать классы, в которых все данные объявлены как static. В этом случае, класс действительно служит только для структуризации. Генерируемый код при этом ничем не будет отличаться от обычного, "бесклассового".
О! Вот про статические классы спасибо - обязательно попробую!
Удачи!
P.S.
А чем в командной строке можно из hex файла получить типа листинг asm?
Хочется таки разобраться, как вызываются функции и грузятся переменные при ссылке на статический класс.
Чтобы не беспокоиться о неоптимальной скорости работы с классами в циклах.
А чем в командной строке можно из hex файла получить типа листинг asm?
Один из способов - использовать avr-objdump.exe. Он может из .elf-файла вытащить очень много интересной и полезной информации. Правда, я им не очень владею - мало пользовался. Но ассемблер, вместе с полученным машинным кодом, можно сгенерировать командой
c:\Arduino\hardware\tools\avr\bin\avr-objdump.exe -d имя_проекта.cpp.elf
Каким-то ключом можно наверно и выходной файл задать - скорее всего -oимя_файла или -Oимя_файла. Но точно не скажу. Я сам просто перенаправлял вывод в командной строке:
c:\Arduino\hardware\tools\avr\bin\avr-objdump.exe -d имя_проекта.cpp.elf >имя_файла.txt
Сам .elf-файл создаётся ардуиносредой где-то во временном каталоге, причём, насколько я понял, каталог при каждом запуске создаётся новый. Не слишком удобно, но можно привыкнуть.
Другой способ - заставить сам компилятор генерить подробный листинг. Но для этого, опять же, надо знать как передать ему определённые ключи, а я такой фокус в ардуине пока не освоил. Помогите кто-нибудь! :)
гугл говорит, что опции можно менять в ардуиновском файле preferences.txt.
Для gcc-компилятора вроде должна помочь опция -Iнаш_global_path. Я попробовал, но ничего не получилось.
Сумел всё-таки. Только не в preferences.txt, а в platform.txt получилось.
И ещё пришлось версию IDE обновить - в старой такого файла не было.