|
Виж темите без отговор | Виж активните теми
Дата и час: Вто Юли 28, 2026 1:18 am
| Автор |
Съобщение |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 C++ и микроконтролери ?
Преправям сега едни неща и се чудя да минавам ли на Ц++ или да не минавам...
Обикновено на един контролер само ANSI C е достатъчно, но аз имам доста код, много над обичайното за един контролер... Налага ми се да правя списъци, стрингове и т.н. в динамична памет и на практика съм си направил доста голяма библиотечка за тия неща на чисто С, но изглежда мнооого грозно.
Основният пронлем ма Ц-то е че всичко се прави със структури а няма наследяване. Примерно ако имам няколко различни структури дето да вкарвам в списъци, правя обща структура чийто хедър е стандартен и на нейна база правя структури "наследници". И после почва лудо тайпкастване...
Сега пробвах Ц++ и template<...> и на първо четене много културно се получават нещата. Но пък изкачат други проблеми. Основният е връзката с нормалното Ц. Поне при GNU ако ползвам шаблони, те са видими само в Ц++ (cpp файлове). Шаблонни функции и шаблонни структури не могат да се експортират. Единственият начин който открих е чрез wraper функции (extern "C") без шаблони.
Другият проблем на шаблоните е, че дори в Ц++ от един файл в друг се експортират само деклрации, но не и дефиниции. Демек притеснява ме, че може би ще дублира код - още не съм го проверил, но май така ще се получи...
Те така сега се двуумя кой път да хвана:
1) Да си остана на Ц с грозните структури и тайпкастове
2) Да ги омешам и да се чудя как да свързвам Ц и Ц++
3) Да мина изцяло на Ц++ поне като компилатор
Кво ша кажете, някой сблъсквал ли се е с такава дилема?
|
| Сря Фев 24, 2010 10:42 am |
|
 |
|
smtp
Ранг: Новодошъл
Регистриран на: Нед Яну 18, 2009 1:28 pm Мнения: 110
|
на MCU никога не съм полвал Ц++ (не ми се е налагало ... а и компилаторите не са много)
от опита ми за PC (а имам голям!) - или само C или само C++
смесването на C и C++ код създава излишни главоболия
когато ползвам стар C код го прехвърлям на C++!
което в 99.99% приключва с преименуването на .C в .CPP
C++ е за предпочитане във всяко отношение (единственно преносимостта е по-проблемна от C)
по отношение на производителност - няма логика C++ да е по-бавен, нито пък кода да е по-обемен (ако същия код решиш да го реализиран само на C!), ... но то зависи от програмиста и задачата
ако приложението ти няма да комуникира с други приложения - класовете са идеалното решение (само ти си ги ползваш)
ако ше обменя данни с други - структурите са единственния работещ вариант!
не съм голям фен на наследяването, и др. екстри на C++ : кода е елегантен ... но може да бъде труден за дебъгване; труден за четене от друг програмист
|
| Сря Фев 24, 2010 12:20 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Това вече го проверих - няма разлика. Говоря за шаблоните, иначе за стандартна С-функция то е ясно че при един и същ сорс и двата компилатора трябва да правят един и същ код. А то при ГНУ даже компилаторите не са два ами си е един...
Единствено се притеснявам за шаблонните функции, щото ГНУ-то бачка на парче - файл по файл... И съм почти сигурен че една и съща функция ще я дублира толкова пъти колкото файла имам, освен линкера да се усеща (но много се съмнявам).
Колкото до трудността... да, ако използвам засукани шаблони или евентуално класове нещата се усложняват. Но те и на чисто Ц не са прости ако имаш много тайпкастинг...
С две думи аз имам Ц++ в наличност и сякаш ще е грехота да не го ползвам 
|
| Сря Фев 24, 2010 1:36 pm |
|
 |
|
bateAz
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 4:11 pm Мнения: 3750 Местоположение: София
|
Aз съм ползвал C++ само когато ми е било наложено, или когато е нямало как. Дори и тогава кодът е бил мешано C/C++. Общо взето културно се напасват, не съм имал сериозни проблеми. Иначе ползвам ANSI C. Имам проекти с до 250К код ( без много коментари ) и според мен даже по-лесно се поддържат от C++. Това, че нямаш наследяване, не можеш да си дефинираш оператори и още много други, май не е велика слабост.
Аз бих те посъветвал, ако наистина държиш да ползваш C++, да го направиш постепенно - в проекта да започнеш да добавяш C++ файлове, старите C да не ги ръчкаш.
|
| Сря Фев 24, 2010 2:36 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Значи едно от нещата за които ми трябва С++ е примерно драйверите на ОС-а. Тия драйвери така или иначе ще се изръчкат понеже минавам от АРМ7 с една периферия към кортекс друга периферия, та затова ако ще го ръчкам сега е момента, после с бой не можеш да ме накараш да пипам нещо работещо....
Другото са библиотеките, които също си плачат за С++ защото имам работа с много стрингове, unicode, динамични памети и т.н.
И не виждам начин как да стане "постепенно" тая работа... Щото навсякъде из С-файловете ползвам или драйвери или библиотеки и проблемът е точно ако от С се ползва С++. Ако беше в обратната посока нямаше да има проблем може би?
А не ми се ще да запазвам Ц-то защото целия код стъпва на "кофти структури". Всичко се бачка през typecast, което първо е източник на много грешки (след тайпкаста компилатора губи нишката) и второ е кофти за дебъгване щото като изкарам структурата тя е от някакъв базов тип. Хайде, GDB позволява да правя тайпкаст и в дебъг конзолата, ама е много грозно всичко това...
Не знам, аз ли не се справям добре с Ц-то или то просто си е недодялано... Е примерно да кажем драйверите. Значи когато се използва драйвер, клиента (нишката) не се интересува какъв е драйвера. Това е начина да се абстрахирам от хардуера. Просто отварям някакъв хендъл и чета и пиша. Не ме интересува дали драйвера е UART, SPI или TCP сокет.
И тая функционалност ми е ценна и дума не може да става за нещо различно. Но за да стане, всички драйвери стъпват върху една абстрактна структура. И кърнела ми работи с такива абстрактни структури. И всичко е толкова абстрактно... Примерно всеки драйвер си има някакъв базов адрес на хардуера, който се пази в структурата на драйвера. Но тъй като пак казвам, че се налага да е абстрактна структура, то указателя вътре в нея е от void * тип. И няма друго яче как да е, щото аз тоя указател го подавам на драйверските структури от една системна функция и тая системна функция изобщо не се интересува какви драйвери имам и не знае с какъв хардуер работят те...
И така като почна да правя имплементация на някакъв конкретен драйвер реално стъпвам върху една абстрактна структура в която нито типовете са наред нито нищо. И трябва да експортирам разни функции дето параметрите са пак абстрактни... И всичко става една "абстрактна боза"....
Понякога предефинирам драйверската структура според типовете на конкретния драйвер, добавям допълнителни полета и т.н. Това малко замазва проблемите, но няма начин или поне на мен не ми е известно как всичко да се изчисти без наследяване или без полиморфизъм или без шаблони... С две думи без С++.
Знам че повечето хора са свикнали с Ц и ще кажат, че е супер, но те просто не им се налага или не искат да правят нещата по начина който описвам...
|
| Сря Фев 24, 2010 3:53 pm |
|
 |
|
Zdrav
Ранг: Форумен бог
Регистриран на: Сря Яну 26, 2005 2:01 pm Мнения: 1952 Местоположение: Варна
|
Миро, не виждам защо се тревожиш да преминеш на С++. Щом си наясно с целта... Едва ли някой тук е по-наясно от теб самия. Ако се използва по-рядко С++ за микроконтролери сигурно е заради това че задачите които се решават най-много стигат до границата на сложноста над която си струва преминаване към С++.
Когато съм използвал С++ съм разглеждал асемблерския листинг и рядко съм виждал излишни неща надробени от компилатора и то веднага ми е идвало на ума как да ги избегна.
_________________ Най-опасният враг на истината и свободата е мнозинството.
|
| Сря Фев 24, 2010 10:29 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
тя целта ми е ясна... но С++ на контролер досега не съм слагал
А то си е особено. Примерно на РС никога не ми се е налагало да правя const class че да го тикам в ROM...
А с темплейти пък нямам никакъв опит и голямо дзверене падна. Примерно ей това ми отне баааая време докато ревърсна кво прави и как го прави...
Повечето неща не знам как да ги направя и което е по-лошо не знам като ги направя дали ще ми хареса... Та затова сондирам за мнения 
|
| Сря Фев 24, 2010 11:10 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Първите ми впечатления от прехода към ++ са много положителни. Поне с GCC засега не срещам никакви проблеми (да чукам на...)
И за всички колеги, които не използват много външен код мога да им кажа че е глупаво да се бачка на С, когато може да се ползва С++.
За да не бъда голословен мога да дам различни примери. Да кажем наследяването. Много често се налагат структури с общ хедър и после различни полета.
На Ц това се прави с вложени структури и нещата изглеждат така:
Същото нещо на Ц++ изглежда така: На пръв поглед разликата е козметична, просто малко по-малко писане и абсолютно еднакъв резултат. В случая обаче примерът е много прост и се "пести" малко писане, обаче като почнат да се правят по-сложни неща "пестенето" става почти логаритмична функция. Но не е само това, при Ц++ има много други екстри като контрол кое поле на кое ниво на абстракция да се ползва, демек public, private, friend... Неща като множествено наследяване, полиморфизъм и т.н. Другата възможност е да се дефинират функции към структурите (казано на С жаргон), иначе при С++ структурата е клас и функциите се наричат методи, но ето директно сравнение: Към С-то добавяме: А С++ се променя на:
Пак подчертавам, че примерите са *абсолютно* идентични като код. Просто Ц++ записа е по-кратък и по-четим, защото указателя към структурата автоматично се каства и се подава като параметър.
Освен това като се работи в интелигентна среда от сорта на Еклипс само като напишеш "структура->" и те се появяват възможните методи и не се налага да помниш дословно имена на функции и да правиш справка в хедъри...
Накратко - С-кодът прехвърлен на С++ без принципни изменения става много по-елегантен и се запазва 100% от резултата, демек *нулев* овърхед.
А от тук нататък може да се говори за истинските ++ неща, дето **нямат** аналог на чисто Ц. За мен това са шаблоните, защото истинската "мизерия" на С се състои в тайпкастовете. В горния пример header структурата е универсална и затова не се налага тайпкаст, но ако има поле с указател тайпкаста става неизбежен на С ...
Шаблоните имат и много други предимства, примерно аз съм свикнал че ако ползвам каквато и да е библиотека това означава да ми се добави доста излишен код.... Но при template library това нещо го няма. Останах удивен след като ползвах някакъв прост шаблон и кода ми набъбна само с около 10-на инструкции. Дето се вика "гледам и не вярвам на ушите си"
Не знам защо се носят митове, че С++ означава много излишен код, огромни библиотеки... Мисълта за това ме е спирала да го разучавам и все чаках както каза Zdrav сложността да стане толкова голяма че да си струва.... Е... Грешил съм!!! Това което виждам, е че С++ е много по-добро решение във всяко отношение. И си струва дори и за най-простия проект!!
|
| Чет Фев 25, 2010 12:51 pm |
|
 |
|
Реконструктор
Ранг: Форумен бог
Регистриран на: Съб Сеп 25, 2004 12:32 pm Мнения: 8382 Местоположение: София
|
Минавай смело. Чистото C няма бъдеще според мен.
Със C++ има някои нюанси, но ще ги бориш с времето.
|
| Чет Фев 25, 2010 1:32 pm |
|
 |
|
zaphod
Ранг: Форумен бог
Регистриран на: Нед Юли 24, 2005 10:28 am Мнения: 2658
|
миро, щом ползваш насилствено наследяване в С програмите си, значи няма място за умуване, минавай. ако темплейтите те тревожат, не ги ползвай, позлвай си само унаследяване. по принцип, темплейтите както ти сам се сети, изискват умен линкер. майкрософтския и интелския се справят, не мога да гарантирам за други, щото не съм ползвал. иначе подхода е следния - темплейта се реализира изцяло в хедъра и се инклудва навсякъде където се ползва. линкера (уж) се грижи да не се дублира кода.
|
| Чет Фев 25, 2010 9:04 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Шаблоните (темплейти) засега основно ги ползвам за структури и се притеснявах дали няма да има проблем с функциите чиито параметри са от шаблонен тип. За щастие няма проблем.
Все още не знам обаче как ще се държи с истинска шаблонна функция. Но засега гледам да запазвам Ц-стила и избягвам шаблонни функции.
Сега по-скоро ме мъчи инициализацията на наследени структури. Малко странно е, но ако добавя метод на обикновено структура си остава структура. Но ако я наследя без дори да има каквито и да е било методи вече се третира като клас. Явно наследяването е само при класовете, докато методите могат да се ползват и при структури.
По принцип това че наследената структура е клас не променя нищо.... освен инициализацията
Ако няма инициализация, всичко е ОК. Но ако има инициализация класът изисква конструктор, само че конструкторът е за run time инициализации. Пък аз си държа някои структури в ROM, тъй че ми трябва compile time инициализация. Пробвах различни трикове, но не можах да го излъжа. Явно за ROM-структурите няма да мога да ползвам наследяване 
|
| Чет Фев 25, 2010 9:57 pm |
|
 |
|
Zdrav
Ранг: Форумен бог
Регистриран на: Сря Яну 26, 2005 2:01 pm Мнения: 1952 Местоположение: Варна
|
Тука нещо не разбрах. Не си успял да направиш compile time инициализация на обект в ROM, който е наследен?
Хммм не разбирам къде е затруднението... Не ползваш ли списък за инициализация в дефиницията на конструктора. В този списък можеш да подаваш стойности за инициализация и на базовите класове. Аз го ползвам това на доста места. Имам обекти чиито данни членове са изцяло в ROM. Това са глобални статични обекти, които се инициализират при компилиране. Конструкторите им в повечето случаи ги оставям да са празни функции. Имат само списък за инициализация.
Може и да не съм разбрал какво имаше впредвид.
_________________ Най-опасният враг на истината и свободата е мнозинството.
|
| Чет Фев 25, 2010 11:47 pm |
|
 |
|
sv_shady
Ранг: Популярен
Регистриран на: Сря Окт 11, 2006 8:19 pm Мнения: 373 Местоположение: София/Edinburgh, UK
|
Добре де аз ли нещо не схващам...? Под шаблони не разбирате ли възможността да се вика една функция с различни типове на аргументите, които всъщност са представлявани от шаблон? Ако съм прав не може ли просто да си дефинираш функцията в подходящия клас? Ако в наследника ти трябва някава разширена версия просто и правиш override, после кеф ти private, public, protected, та дори friend.
|
| Пет Фев 26, 2010 12:47 am |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Шаблонната функция използва един или повече абстрактни типове и/или параметри. Те са абстрактни както по времето на деклариране, така и по времето на дефиниране ма функцията. Стават известни едва след като някъде извикаш функцията. Идеята е, че пишеш шаблона веднъж а после го ползваш с каквото ти падне. Същото нещо може да се постигне и с overloaded функции. Веднъж в дефинираш за един тип, после дефинираш същата функция с друг тип. Разликата е, че шаблонът се дефинира веднъж, докато overload-натите функции трябва да дефинираш многократно (веднъж за всеки нов тип). Другият вариант е с класове, но пак трябва да override-ваш многократно... С две думи предимствата на шаблона е, че подобно на макрос го пишеш веднъж и после го ползваш, колкото пъти искаш с каквито типове искаш. За всяка комбинация той автоматично създава overload-ната или override-ната функция, които иначе ти изрично би трябвало да напишеш. Недостатъкът обаче е, че евентуално (не съм проверил) ако един и същ шаблон се ползва в два различни сорс файла ще създаде две идентични функции, демек ще се дублира код. Докато ако работиш сам с over-нати функциии ще я направиш веднъж и ще я експортираш....
Ми пробвам, ама нещо не се получава... и не знам къде бъркам
Значи ако инициализацията е с константа, еднаква за всички инстанции - става, но това не ми върши работа. Аз искам стойностите да ги задавам не в декларацията, а в дефиницията.
Ето ти пример:
 |  |  |  | Код: // Това е базова структура за всички драйвери - шаблон за ROM template<typename HW_TYPE, typename DRV_DATA> struct DRV_INFO_t { unsigned char drv_index; unsigned char signal; unsigned char hw_id; unsigned char smr;
HW_TYPE *hw_base; void (*isr)(DRV_INFO_t *info, HW_TYPE *hw_base); unsigned int (*dcr)(DRV_INFO_t *info, unsigned int reason, void *param); void (*dsr)(DRV_INFO_t *info, DRV_DATA *data, HANDLE hnd); DRV_DATA *data;
};
// Тук конкретен драйвер (SYSTICK)
//първо шаблон за RAM структурата на драйвера struct DRV_SYSTICK_DATA :DRV_DATA {
};
// Сега вече мога да попълня шаблона на SYSTICK, но първо го typedef-вам typedef DRV_INFO_t<CPU_SYSTICK, DRV_SYSTICK_DATA> DRV_SYSTICK_BASE;
// Ето го и наследяването... struct DRV_SYSTICK_INFO_t: DRV_SYSTICK_BASE { unsigned int systick_div;
// Ето тук трябва да има конструктор: инициализираш списък.....
};
//малко декларации (драйверските функции) RES_CODE SYSTICK_DCR(DRV_SYSTICK_INFO_t *info, unsigned int reason, void *param); void SYSTICK_DSR(DRV_SYSTICK_INFO_t *info, DRV_SYSTICK_DATA *data, HANDLE hnd); void SYSTICK_ISR(DRV_SYSTICK_INFO_t *info, CPU_SYSTICK_t *hw_base);
//сега вече мога да правя една или повече "инстанции" на драйвера, като за целта всяка инстанция трябва да има INFO (ROM) и DATA(RAM) структури
//ето дата-та DRV_SYSTICK_DATA drv_systick_data;
//ето инфо-то const DRV_SYSTICK_INFO_t drv_systick_info = { 0, 0, 0, 0, CPU_SYSTICK, SYSTICK_ISR, SYSTICK_DCR, SYSTICK_DSR, &drv_systick_data
};
|  |  |  |  |
Значи проблемите се първо в конструктора на info структурата - нещо не мога да го направя...
И второ const дефиницията на info-то - в случая ползвам = {...} което е начина за инициализация на обикновени структури. За наследените трябва "=" да се махне и вместо фигурни скобки да са нормални скобки - демек викане на конструктор. Но както и да го въртя, все нещо компилатора не е щастлив. Затова и не ползвам наследяване още... (макар че ми се иска).
бтв, ползвам указатели на функции и може и заради тях нещо да се опетлавам... То реално мога да ги сложа като виртуални методи, но в случая тия функции ги викам от кърнела и обикновено от асемблер. Просто заради бързодействие и други причини не искам да минавам през виртуални таблици... Иначе с виртуални методи ще стане много по-прегледно, но...
|
| Пет Фев 26, 2010 10:31 am |
|
 |
|
smtp
Ранг: Новодошъл
Регистриран на: Нед Яну 18, 2009 1:28 pm Мнения: 110
|
мисля, че няма начин да се дублира код - просто защото C++ компилатора генерира уникални имена на функциите (но еднакви за идентичните функции - според брой и тип на параметрите ...!).
а линкера просто игнорира дублираните функции ... (не е необходимо да е умен!)
сигурно има C++ компилатори дето не се справят добре с шаблоните (дублиран код ...), но ... това лесно можеш да го провериш 
|
| Пет Фев 26, 2010 11:05 am |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 3 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|