Pytanie
Mam dwa kompilatory na moim sprzęcie C ++ i C89
Myślę o użyciu C ++ z klasami, ale bez polimorfizmu (aby uniknąć vtables). Główne powody, dla których chciałbym używać C ++ to:
- Wolę używać funkcji „inline” zamiast definicji makr.
- Chciałbym używać przestrzeni nazw, ponieważ prefiksy zaśmiecają kod.
- Uważam, że C ++ jest trochę bezpieczniejszy, głównie z powodu szablonów i szczegółowego rzutowania.
- Bardzo lubię przeciążone funkcje i konstruktory (używane do automatycznego rzutowania).
Czy widzisz jakiś powód, aby pozostać przy C89 podczas tworzenia oprogramowania dla bardzo ograniczonego sprzętu (4kb pamięci RAM)?
Wniosek
Dziękuję za odpowiedzi, były naprawdę pomocne!
Przemyślałem temat i pozostanę przy C głównie dlatego, że:
- Łatwiej jest przewidzieć rzeczywisty kod w C i jest to naprawdę ważne, jeśli masz tylko 4kb pamięci RAM.
- Mój zespół składa się głównie z programistów C, więc zaawansowane funkcje C ++ nie będą często używane.
- Znalazłem sposób na wbudowane funkcje w moim kompilatorze C (C89).
Trudno zaakceptować jedną odpowiedź, ponieważ podałeś tak wiele dobrych odpowiedzi. Niestety nie mogę stworzyć wiki i zaakceptować go, więc wybiorę jedną odpowiedź, która zmusiła mnie do myślenia.
Odpowiedzi:
Dwa powody używania C zamiast C ++:
Również pierwotne pytanie i szereg komentarzy wspominają o 4 Kb pamięci RAM . W przypadku typowego procesora wbudowanego ilość pamięci RAM jest (w większości) niezwiązana z rozmiarem kodu, ponieważ kod jest przechowywany i uruchamiany z pamięci flash.
Z pewnością ilość miejsca do przechowywania kodu jest czymś, o czym należy pamiętać, ale ponieważ na rynku pojawiają się nowe, bardziej pojemne procesory, jest to mniejszy problem niż kiedyś w przypadku wszystkich projektów, z wyjątkiem najbardziej wrażliwych na koszty.
O wykorzystaniu podzbioru C ++ do użytku z systemami wbudowanymi: istnieje teraz standard MISRA C ++ , któremu warto przyjrzeć się.
EDYCJA: Zobacz także to pytanie , które doprowadziło do debaty na temat C vs C ++ dla systemów wbudowanych.
źródło
W przypadku celu o bardzo ograniczonych zasobach, takiego jak 4KB pamięci RAM, przetestowałbym wody z kilkoma próbkami przed podjęciem dużego wysiłku, którego nie można łatwo przenieść z powrotem do czystej implementacji ANSI C.
Grupa robocza Embedded C ++ zaproponowała standardowy podzbiór języka i standardowy podzbiór biblioteki standardowej. Niestety, straciłem z oczu ten wysiłek, gdy zmarł Dziennik użytkownika C. Wygląda na to, że w Wikipedii jest artykuł , a komitet nadal istnieje.
W środowisku osadzonym naprawdę trzeba uważać na alokację pamięci. Aby wymusić tę opiekę, może być konieczne zdefiniowanie globalnego
operator new()
i jego przyjaciół z czymś, czego nie można nawet powiązać, aby wiedzieć, że nie jest używane.new
Z drugiej strony miejsce docelowe może być twoim przyjacielem, jeśli jest używane rozsądnie wraz ze stabilnym, bezpiecznym dla wątków i gwarantowanym schematem alokacji.Funkcje wbudowane nie będą stanowiły większego problemu, chyba że są na tyle duże, że powinny być funkcjami prawdziwymi. Oczywiście makra, które zostały zastąpione, miały ten sam problem.
Szablony też mogą nie powodować problemu, chyba że ich instancja działa w amoku. Dla każdego szablonu, którego używasz, przeprowadź audyt wygenerowanego kodu (mapa linków może zawierać wystarczające wskazówki), aby upewnić się, że wystąpiły tylko instancje, których zamierzałeś użyć.
Innym problemem, który może się pojawić, jest zgodność z debugerem. Nie jest niczym niezwykłym, że debugger sprzętowy, który może być używany w inny sposób, ma bardzo ograniczoną obsługę interakcji z oryginalnym kodem źródłowym. Jeśli musisz skutecznie debugować w asemblerze, to interesujące zniekształcanie nazw w C ++ może dodać dodatkowe zamieszanie do zadania.
RTTI, dynamiczne rzutowanie, wielokrotne dziedziczenie, ciężki polimorfizm i wyjątki - wszystko to wiąże się z pewnym kosztem czasu wykonania. Niektóre z tych funkcji kosztują cały program, jeśli są używane, inne po prostu zwiększają wagę klas, które ich potrzebują. Poznaj różnicę i mądrze wybieraj zaawansowane funkcje, mając pełną wiedzę przynajmniej na temat pobieżnej analizy kosztów i korzyści.
W małym, wbudowanym środowisku będziesz łączył się bezpośrednio z jądrem czasu rzeczywistego lub działał bezpośrednio na sprzęcie. Tak czy inaczej, będziesz musiał upewnić się, że kod startowy środowiska wykonawczego poprawnie obsługuje określone zadania C ++ związane z uruchamianiem. Może to być tak proste, jak upewnienie się, że używasz odpowiednich opcji konsolidatora, ale ponieważ często ma się bezpośrednią kontrolę nad źródłem do punktu wejścia resetowania zasilania, może być konieczne przeprowadzenie audytu, aby upewnić się, że robi wszystko. Na przykład na platformie ColdFire, nad którą pracowałem, narzędzia deweloperskie były dostarczane z modułem CRT0.S, który zawierał inicjatory C ++, ale był komentowany. Gdybym użył go prosto z pudełka, byłbym zdziwiony globalnymi obiektami, których konstruktorzy w ogóle nie działali.
Ponadto w środowisku osadzonym często konieczne jest zainicjowanie urządzeń sprzętowych, zanim będzie można ich użyć, a jeśli nie ma systemu operacyjnego ani programu ładującego, to robi to Twój kod. Będziesz musiał pamiętać, że konstruktory obiektów globalnych są uruchamiane przed
main()
wywołaniem, więc będziesz musiał zmodyfikować lokalny CRT0.S (lub jego odpowiednik), aby inicjalizacja sprzętu została wykonana przed wywołaniem samych konstruktorów globalnych. Oczywiście na szczytmain()
jest już za późno.źródło
Nie. Podczas programowania osadzonego można uniknąć wszelkich funkcji języka C ++, które mogą powodować problemy (polimorfizm w czasie wykonywania, RTTI itp.). Istnieje społeczność programistów embedded C ++ (pamiętam, że czytałem kolumny programistów embedded używających C ++ w starym dzienniku użytkowników C / C ++) i nie mogę sobie wyobrazić, żeby byli bardzo głośni, gdyby wybór był tak zły.
źródło
Raport Techniczny na C ++ Wydajność jest doskonałym przewodnikiem dla tego rodzaju rzeczy. Zwróć uwagę, że zawiera on sekcję dotyczącą problemów związanych z programowaniem wbudowanym!
Ponadto ++ na wzmiankę o Embedded C ++ w odpowiedziach. Standard nie jest w 100% zgodny z moim gustem, ale jest dobrym punktem odniesienia przy podejmowaniu decyzji, które części C ++ możesz porzucić.
Podczas programowania dla małych platform wyłączamy wyjątki i RTTI, unikamy dziedziczenia wirtualnego i zwracamy szczególną uwagę na liczbę funkcji wirtualnych, które mamy w pobliżu.
Twój przyjaciel jest jednak mapą konsolidatora: sprawdzaj ją często, a szybko zauważysz źródła kodu i pamięć statyczną.
Następnie obowiązują standardowe uwagi dotyczące wykorzystania pamięci dynamicznej: w środowisku tak ograniczonym, jak to, o którym wspomniałeś, możesz w ogóle nie używać alokacji dynamicznych. Czasami możesz uciec z pulami pamięci dla małych alokacji dynamicznych lub alokacją opartą na ramkach, gdzie wstępnie przydzielasz blok i wyrzucasz całość później.
źródło
Zalecam używanie kompilatora C ++, ale ograniczam użycie specyficznych funkcji C ++. Możesz programować jak C w C ++ (środowisko wykonawcze C jest zawarte w C ++, chociaż w większości wbudowanych aplikacji i tak nie korzystasz z biblioteki standardowej).
Możesz śmiało używać klas C ++ itp. Po prostu
źródło
Jako inżynier oprogramowania układowego / systemów wbudowanych mogę wam powiedzieć, dlaczego C jest nadal najlepszym wyborem w stosunku do C ++ i tak, biegle posługuję się obydwoma.
1) Niektóre cele, które opracowujemy, mają 64 kB pamięci RAM zarówno dla kodu, jak i danych, więc musisz upewnić się, że liczy się każdy bajt, i tak, zajmowałem się optymalizacją kodu, aby zaoszczędzić 4 bajty, które kosztowały mnie 2 godziny, i to jest w 2008.
2) Każda funkcja biblioteki C jest sprawdzana, zanim umieścimy ją w ostatecznym kodzie, ze względu na ograniczenie rozmiaru, więc wolimy, aby ludzie nie używali dzielenia (brak dzielnika sprzętowego, więc potrzebna jest duża biblioteka), malloc (ponieważ nie mamy sterty , cała pamięć jest przydzielana z bufora danych w 512-bajtowej porcji i musi zostać przejrzana przez kod) lub inne praktyki zorientowane obiektowo, które niosą ze sobą dużą karę. Pamiętaj, liczy się każda funkcja biblioteki, której używasz.
3) Słyszałeś kiedyś o nakładce terminu? masz tak mało miejsca na kod, że czasami musisz zamienić coś z innym zestawem kodu. Jeśli wywołujesz funkcję biblioteczną, wówczas funkcja biblioteki musi być rezydentna. Jeśli używasz go tylko w funkcji nakładki, marnujesz dużo miejsca, polegając na zbyt wielu metodach obiektowych. Więc nie zakładaj żadnej funkcji biblioteki C, nie mówiąc już o akceptacji C ++.
4) Odlewanie, a nawet pakowanie (gdzie niewyrównana struktura danych przekracza granice słów) jest potrzebne ze względu na ograniczoną konstrukcję sprzętu (np. Silnik ECC, który jest podłączony w określony sposób) lub w celu radzenia sobie z błędem sprzętowym. Nie możesz zakładać zbyt wiele w sposób niejawny, więc dlaczego obiekt zbytnio go orientuje?
5) Najgorszy scenariusz: wyeliminowanie niektórych metod obiektowych zmusi programistę do myślenia, zanim użyją zasobów, które mogą eksplodować (tj. Przydzielenie 512 bajtów na stos zamiast z bufora danych) i zapobiegnie niektórym z potencjalnych najgorszych scenariuszy, które nie są testowane ani nie eliminują całej ścieżki kodu.
6) Używamy dużej abstrakcji, aby chronić sprzęt przed oprogramowaniem i uczynić kod możliwie najbardziej przenośnym i przyjaznym dla symulacji. Dostęp sprzętowy musi być opakowany w makro lub funkcję wbudowaną, które są warunkowo kompilowane między różnymi platformami, typ danych musi być rzutowany jako rozmiar bajtu, a nie określony cel, bezpośrednie użycie wskaźnika jest niedozwolone (ponieważ niektóre platformy zakładają, że we / wy mapowane w pamięci jest tak samo jak pamięć danych) itp.
Mogę wymyślić więcej, ale masz pomysł. My, ludzie zajmujący się oprogramowaniem sprzętowym, mamy szkolenie zorientowane obiektowo, ale zadanie systemu wbudowanego może być tak zorientowane sprzętowo i na niskim poziomie, że nie jest z natury wysokopoziomowe ani abstrakcyjne.
Przy okazji, każda praca oprogramowania układowego, w której byłem, wykorzystuje kontrolę źródła, nie wiem, skąd wziął się ten pomysł.
- jakiś gość od oprogramowania firmy SanDisk.
źródło
Dlaczego ludzie to mówią? Ty nie wiesz, co każda linia C robi chyba sprawdzić wyjście asm. To samo dotyczy C ++.
Na przykład, co asm daje to niewinne stwierdzenie:
a[i] = b[j] * c[k];
Wygląda to dość niewinnie, ale kompilator oparty na gcc tworzy ten asm dla 8-bitowego mikro
CLRF 0x1f, ACCESS RLCF 0xfdb, W, ACCESS ANDLW 0xfe RLCF 0x1f, F, ACCESS MOVWF 0x1e, ACCESS MOVLW 0xf9 MOVF 0xfdb, W, ACCESS ADDWF 0x1e, W, ACCESS MOVWF 0xfe9, ACCESS MOVLW 0xfa MOVF 0xfdb, W, ACCESS ADDWFC 0x1f, W, ACCESS MOVWF 0xfea, ACCESS MOVFF 0xfee, 0x1c NOP MOVFF 0xfef, 0x1d NOP MOVLW 0x1 CLRF 0x1b, ACCESS RLCF 0xfdb, W, ACCESS ANDLW 0xfe RLCF 0x1b, F, ACCESS MOVWF 0x1a, ACCESS MOVLW 0xfb MOVF 0xfdb, W, ACCESS ADDWF 0x1a, W, ACCESS MOVWF 0xfe9, ACCESS MOVLW 0xfc MOVF 0xfdb, W, ACCESS ADDWFC 0x1b, W, ACCESS MOVWF 0xfea, ACCESS MOVFF 0xfee, 0x18 NOP MOVFF 0xfef, 0x19 NOP MOVFF 0x18, 0x8 NOP MOVFF 0x19, 0x9 NOP MOVFF 0x1c, 0xd NOP MOVFF 0x1d, 0xe NOP CALL 0x2142, 0 NOP MOVFF 0x6, 0x16 NOP MOVFF 0x7, 0x17 NOP CLRF 0x15, ACCESS RLCF 0xfdf, W, ACCESS ANDLW 0xfe RLCF 0x15, F, ACCESS MOVWF 0x14, ACCESS MOVLW 0xfd MOVF 0xfdb, W, ACCESS ADDWF 0x14, W, ACCESS MOVWF 0xfe9, ACCESS MOVLW 0xfe MOVF 0xfdb, W, ACCESS ADDWFC 0x15, W, ACCESS MOVWF 0xfea, ACCESS MOVFF 0x16, 0xfee NOP MOVFF 0x17, 0xfed NOP
Liczba wyprodukowanych instrukcji zależy w dużej mierze od:
Jest to szczególnie prawdziwe w małym, wbudowanym świecie, w którym procesory po prostu nie są skonfigurowane do obsługi C.Więc moja odpowiedź byłaby taka, że C i C ++ są tak samo złe, jak siebie nawzajem, chyba że zawsze sprawdzasz wyjście asm, w takim przypadku są tak samo dobrzy jak inni.
Hugo
źródło
Słyszałem, że niektórzy wolą C do pracy osadzonej ze względu na fakt, że jest prostszy, a zatem łatwiejszy do przewidzenia faktycznego kodu, który zostanie wygenerowany.
Osobiście uważam, że pisanie C ++ w stylu C (przy użyciu szablonów dla bezpieczeństwa typów) dałoby ci wiele korzyści i nie widzę żadnego prawdziwego powodu, aby tego nie robić.
źródło
Nie widzę powodu, aby używać C zamiast C ++. Cokolwiek potrafisz zrobić w C, możesz to również zrobić w C ++. Jeśli chcesz uniknąć narzutów VMT, nie używaj metod wirtualnych i polimorfizmu.
Jednak C ++ może dostarczyć bardzo przydatnych idiomów bez narzutu. Jednym z moich ulubionych jest RAII. Zajęcia niekoniecznie są drogie pod względem pamięci lub wydajności ...
źródło
Napisałem kod dla paltform osadzonego w ARM7 w IAR Workbench. Zdecydowanie zalecam korzystanie z szablonów w celu optymalizacji czasu kompilacji i przewidywania ścieżki. Unikaj dynamicznego rzucania jak zarazy. Użyj cech / zasad na swoją korzyść, zgodnie z zaleceniami w książce Andrei Alexandrescu, Modern C ++ design .
Wiem, że może to być trudne do nauczenia, ale jestem też pewien, że Twój produkt skorzysta na takim podejściu.
źródło
Dobry powód, a czasami jedyny, jest taki, że wciąż nie ma kompilatora C ++ dla konkretnego systemu wbudowanego. Tak jest na przykład w przypadku mikrokontrolerów Microchip PIC . Są bardzo łatwe do napisania i mają darmowy kompilator C (właściwie niewielki wariant C), ale w zasięgu wzroku nie ma kompilatora C ++.
źródło
W przypadku systemu ograniczonego do 4K pamięci RAM użyłbym C, a nie C ++, tylko po to, aby mieć pewność, że zobaczysz wszystko, co się dzieje. C ++ polega na tym, że bardzo łatwo jest użyć znacznie większej ilości zasobów (zarówno procesora, jak i pamięci), niż wygląda na to, by spojrzeć na kod. (Och, po prostu utworzę kolejny BlerfObject, aby to zrobić ... ups! Z pamięci!)
Możesz to zrobić w C ++, jak już wspomniano (bez RTTI, bez vtables itp.), Ale spędzisz tyle czasu, aby upewnić się, że korzystanie z C ++ nie ucieknie od Ciebie, jak w przypadku odpowiednika w C .
źródło
Umysł ludzki radzi sobie ze złożonością, oceniając jak najwięcej, a następnie decydując, na czym jest ważne, aby się skupić, a resztę odrzuca lub amortyzuje. To jest cała podstawa budowania marki w marketingu, a przede wszystkim ikony.
Aby zwalczyć tę tendencję, wolę C od C ++, ponieważ zmusza cię to do myślenia o swoim kodzie i jego ściślejszej interakcji ze sprzętem - nieustannie blisko.
Z długiego doświadczenia jestem przekonany, że C zmusza cię do wymyślania lepszych rozwiązań problemów, po części poprzez zejście z drogi i nie zmuszanie cię do marnowania dużo czasu na spełnienie ograniczenia, który niektórzy kompilatorzy uważali za dobry pomysł lub dowiedzieć się, co się dzieje „pod kołdrą”.
W tym duchu języki niskiego poziomu, takie jak C, sprawiają, że spędzasz dużo czasu skupiając się na sprzęcie i budowaniu dobrych pakietów struktury danych / algorytmów, podczas gdy języki wysokiego poziomu sprawiają, że spędzasz dużo czasu na drapaniu się po głowie, zastanawiając się, co się tam dzieje. i dlaczego nie możesz zrobić czegoś całkiem rozsądnego w swoim konkretnym kontekście i środowisku. Przekonanie kompilatora do złożenia (mocne pisanie jest największym winowajcą) NIE jest produktywnym wykorzystaniem czasu.
Pewnie dobrze pasuję do formy programisty - lubię sterowanie. Moim zdaniem to nie jest wada osobowości programisty. Płacą nam za to kontrola. Mówiąc dokładniej, BEZPRAWIDŁOWA kontrola. C daje znacznie większą kontrolę niż C ++.
źródło
Osobiście z 4kb pamięci powiedziałbym, że nie uzyskasz dużo więcej kilometrów z C ++, więc po prostu wybierz taką, która wydaje się najlepszą kombinacją kompilator / środowisko uruchomieniowe do tego zadania, ponieważ język prawdopodobnie nie będzie miał większego znaczenia.
Zauważ, że i tak nie chodzi tylko o język, ponieważ liczy się również biblioteka. Często biblioteki C mają nieco mniejszy minimalny rozmiar, ale mogę sobie wyobrazić, że biblioteka C ++ przeznaczona do programowania osadzonego jest ograniczona, więc koniecznie przetestuj.
źródło
C wygrywa w przenośności - ponieważ jest mniej niejednoznaczny w specyfikacji językowej; dlatego oferuje znacznie lepszą przenośność i elastyczność między różnymi kompilatorami itp. (mniej problemów).
Jeśli nie zamierzasz wykorzystywać funkcji C ++ do zaspokojenia potrzeb, wybierz C.
źródło
unsigned mul(unsigned short x, unsigned short y) { return x*y;}
jak nie skutki uboczne, nawet jeśli produkt przekracza 2147483647, lub które należy uznaćvoid get_float_bits(float *fp, uint32_t n) { *(uint32_t)fp = n; }
za potencjalnie zmieniające wartość afloat
].Osobiście, jeśli chodzi o aplikacje wbudowane (kiedy mówię o osadzonych, nie mam na myśli dzisiejszych urządzeń wbudowanych winCE, iPhone itp.). Mam na myśli urządzenia o ograniczonych zasobach. Wolę C, chociaż całkiem sporo pracowałem z C ++.
Na przykład urządzenie, o którym mówisz, ma 4kb pamięci RAM, cóż, właśnie z tego powodu nie rozważałbym C ++. Jasne, możesz zaprojektować coś małego za pomocą C ++ i ograniczyć użycie tego w swojej aplikacji, tak jak sugerowały to inne posty, ale C ++ „może” potencjalnie skomplikować / rozdęć aplikację pod osłonami.
Czy zamierzasz łączyć się statycznie? Możesz chcieć porównać statyczną aplikację fikcyjną przy użyciu c ++ vs c. To może doprowadzić do rozważenia zamiast tego C. Z drugiej strony, jeśli jesteś w stanie zbudować aplikację C ++ w ramach swoich wymagań dotyczących pamięci, zrób to.
IMHO, Ogólnie rzecz biorąc, w aplikacjach wbudowanych lubię wiedzieć wszystko, co się dzieje. Kto korzysta z pamięci / zasobów systemowych, ile i dlaczego? Kiedy je uwalniają?
Podczas programowania dla celu z X ilością zasobów, procesorem, pamięcią itp. Staram się pozostać po niższej stronie korzystania z tych zasobów, ponieważ nigdy nie wiesz, jakie przyszłe wymagania się pojawią, dlatego musisz dodać więcej kodu do projektu, który miał być prostą, małą aplikacją, ale w końcu stał się znacznie większy.
źródło
O moim wyborze decyduje zazwyczaj biblioteka C, z której zdecydujemy się skorzystać, która jest wybierana na podstawie tego, co urządzenie musi zrobić. Tak więc 9/10 razy… kończy się na uclibc lub newlib i C. Jądro, którego używamy, ma na to duży wpływ, lub jeśli piszemy własne jądro.
To także wybór wspólnej płaszczyzny. Większość dobrych programistów C nie ma problemu z używaniem C ++ (mimo że przez cały czas wielu narzeka, że go używają) .. ale nie znalazłem odwrotności (z mojego doświadczenia).
W projekcie, nad którym pracujemy (który wymaga od podstaw jądra), większość rzeczy jest wykonywana w C, jednak mały stos sieciowy został zaimplementowany w C ++, ponieważ po prostu łatwiej i mniej problematycznie było zaimplementować sieć w C ++.
Efekt końcowy jest taki, że urządzenie albo będzie działać i przejdzie testy akceptacyjne, albo nie. Jeśli możesz zaimplementować ograniczenia foo na stosie xx i yy sterty za pomocą języka z, idź do tego i użyj wszystkiego, co sprawia, że jesteś bardziej produktywny.
Moje osobiste preferencje to C, ponieważ:
Tak, czuję się dobrze z C ++, ale nie znam go tak dobrze, jak standardowe C.
Teraz, jeśli możesz powiedzieć coś odwrotnego, użyj tego, co wiesz :) Jeśli to działa, przechodzi testy itp. W czym problem?
źródło
Ile masz ROM / FLASH?
4kB pamięci RAM może nadal oznaczać, że istnieją setki kilobajtów pamięci FLASH do przechowywania rzeczywistego kodu i danych statycznych. Pamięć RAM o tym rozmiarze jest zwykle przeznaczona tylko dla zmiennych, a jeśli będziesz ostrożny z tymi, możesz zmieścić w pamięci dość duży program pod względem linii kodu.
Jednak C ++ ma tendencję do utrudniania umieszczania kodu i danych w pamięci FLASH ze względu na reguły konstrukcji obiektów w czasie wykonywania. W języku C stałą strukturę można łatwo umieścić w pamięci FLASH i uzyskać do niej dostęp jako obiekt stałej sprzętowej. W C ++ stały obiekt wymagałby od kompilatora oceny konstruktora w czasie kompilacji, co moim zdaniem wykracza poza to, co może zrobić kompilator C ++ (teoretycznie można to zrobić, ale w praktyce jest to bardzo trudne) .
Tak więc w środowisku typu „mała pamięć RAM”, „duży FLASH” mógłbym używać C. każdego dnia. Zauważ, że dobrym wyborem pośrednim jest C99, który ma większość fajnych funkcji C ++ dla kodu nieopartego na klasach.
źródło
Ogólnie nie. C ++ to super zestaw C. Byłoby to szczególnie prawdziwe w przypadku nowych projektów.
Jesteś na dobrej drodze do unikania konstrukcji C ++, które mogą być kosztowne pod względem czasu procesora i zużycia pamięci.
Zwróć uwagę, że niektóre rzeczy, takie jak polimorfizm, mogą być bardzo cenne - są zasadniczo wskaźnikami funkcji. Jeśli uznasz, że ich potrzebujesz, korzystaj z nich - mądrze.
Ponadto dobra (dobrze zaprojektowana) obsługa wyjątków może sprawić, że osadzona aplikacja będzie bardziej niezawodna niż aplikacja, która obsługuje rzeczy z tradycyjnymi kodami błędów.
źródło
W przypadku problemu z alokacją pamięci mogę polecić użycie platformy Quantum i jej podejścia do automatu stanowego, ponieważ przydziela wszystko, czego potrzebujesz w czasie inicjalizacji. Pomaga również złagodzić problemy związane z rywalizacją.
Ten produkt działa w językach C i C ++.
źródło
Niektórzy twierdzą, że kompilatory C mogą generować znacznie wydajniejszy kod, ponieważ nie muszą obsługiwać zaawansowanych funkcji C ++ i dlatego mogą być bardziej agresywne w swoich optymalizacjach.
Oczywiście w tym przypadku możesz chcieć przetestować dwa konkretne kompilatory.
źródło
Jedynym powodem, dla którego wolisz C IMHO, byłoby to, że kompilator C ++ dla twojej platformy nie jest w dobrym stanie (błędny, słaba optymalizacja itp.).
źródło
Książka C ++ dla programistów gier zawiera informacje dotyczące tego, kiedy zwiększy się rozmiar kodu na podstawie funkcji z C ++.
źródło
Masz inline w C99. Może lubisz lekarzy, ale kwestia właściwego doboru lekarzy może być kłopotliwa. Jeśli jedynym powodem, dla którego nie należy używać C, są przestrzenie nazw, naprawdę trzymałbym się C89. Dzieje się tak, ponieważ możesz chcieć przenieść go na nieco inną wbudowaną platformę. Możesz później zacząć pisać w C ++ na tym samym kodzie. Ale uważaj na następujące, gdzie C ++ NIE jest nadzbiorem C. Wiem, że powiedziałeś, że masz kompilator C89, ale i tak czy to porównanie C ++ z C99, ponieważ na przykład pierwszy element jest prawdziwy dla dowolnego C od K&R.
sizeof 'a' > 1 w C, nie w C ++. W C masz tablice o zmiennej długości VLA. Przykład: func (int i) {int a [i] . W C masz zmienne składowe tablicy VAM. Przykład: struct {int b; int m [];} .
źródło
To zależy od kompilatora.
Nie wszystkie wbudowane kompilatory implementują całe C ++, a nawet jeśli to robią, mogą nie być dobre w unikaniu nadmiaru kodu (co jest zawsze ryzykiem w przypadku szablonów). Przetestuj go z kilkoma mniejszymi programami i sprawdź, czy nie napotkasz żadnych problemów.
Ale biorąc pod uwagę dobry kompilator, nie, nie ma powodu, aby nie używać C ++.
źródło
Chcę tylko powiedzieć, że nie ma systemu z „NIEOGRANICZONYMI” zasobami. Wszystko na tym świecie jest ograniczone i KAŻDA aplikacja powinna uwzględniać wykorzystanie zasobów, niezależnie od tego, czy jest to ASM, C, JAVA czy JavaScript. Manekiny, które przydzielają kilka MB "dla pewności", sprawiają, że iPhone 7, Pixel i inne urządzenia są wyjątkowo obciążone. Nieważne, czy masz 4kb czy 40 Gb.
Ale z drugiej strony, aby przeciwstawić się marnotrawieniu zasobów - jest czas potrzebny na ich oszczędzenie. Jeśli potrzeba 1 tygodnia więcej, aby napisać prostą rzecz w C, aby zaoszczędzić kilka taktów i kilka bajtów, zamiast używać C ++ już zaimplementowanego, przetestowanego i rozpowszechnionego. Po co się męczyć? To jak kupowanie koncentratora USB. tak, możesz to zrobić sam, ale czy będzie lepiej? bardziej wiarygodne? taniej, jeśli liczysz swój czas?
Na marginesie - nawet moc z gniazdka nie jest nieograniczona. Spróbuj zbadać, skąd się bierze, a zobaczysz, że głównie coś pali. Prawo energii i materiału jest nadal aktualne: żaden materiał ani energia nie pojawia się ani nie znika, ale raczej się przekształca.
źródło
Właśnie znalazłem przykład, jak używać ISO C ++ do programowania systemów wbudowanych, który może być interesujący dla kogoś, kto podejmuje decyzję za każdym razem, gdy używa C ++ lub C.
Został dostarczony przez Bjarne Stroustrup na jego stronie internetowej :
Aby zobaczyć, jak ISO C ++ można wykorzystać do programowania poważnych systemów wbudowanych, zobacz standardy kodowania C ++ pojazdów lotniczych JSF .
źródło
Różne odpowiedzi dotyczą innego aspektu pytania:
„malloc”
Niektóre poprzednie odpowiedzi dużo o tym mówią. Dlaczego w ogóle myślisz, że to połączenie istnieje? W przypadku naprawdę małej platformy malloc jest zwykle niedostępny lub zdecydowanie opcjonalny. Wdrożenie dynamicznej alokacji pamięci ma sens, gdy masz RTOS w dolnej części systemu - ale do tego czasu jest to czysto niebezpieczne.
Bez niej można zajść bardzo daleko. Pomyśl tylko o wszystkich starych programach FORTRAN, które nie miały nawet odpowiedniego stosu dla zmiennych lokalnych ...
źródło
Na całym świecie jest wielu różnych producentów kontrolerów, a kiedy przyjrzysz się ich projektom i zestawom instrukcji, których należy użyć do skonfigurowania, możesz mieć wiele problemów. Główną wadą języka asemblera jest zależność od maszyny / architektury. To naprawdę ogromne wymaganie od programisty, aby zapamiętał wszystkie zawarte tam instrukcje, aby wykonać kodowanie dla różnych kontrolerów. Dlatego C stał się bardziej popularny w programowaniu wbudowanym, ponieważ C jest wystarczająco wysoki, aby wyodrębnić algorytmy i struktury danych ze szczegółów zależnych od sprzętu, dzięki czemu kod źródłowy można przenosić na szeroką gamę docelowego sprzętu, język niezależny od architektury i bardzo łatwy do konwertować i utrzymywać kod. Ale widzimy niektóre języki wysokiego poziomu (zorientowane obiektowo), takie jak C, C ++, Python, Java itp.
źródło
Polecam C ++ z ograniczeniami i uwagami.
Czas na wprowadzenie na rynek i łatwość konserwacji. Programowanie w C ++ jest łatwiejsze i szybsze. Więc jeśli jesteś w fazie projektowania, wybierz kontroler wystarczająco dobry, aby używać C ++. (Należy pamiętać, że niektóre rynki o dużym wolumenie wymagają możliwie najniższych kosztów, na których nie można dokonać tego wyboru).
Prędkość. C może być szybsze niż C ++, ale upewnij się, że przyrost szybkości nie jest duży. Możesz więc przejść do C ++. Opracuj swoje algorytmy, przetestuj je i przyspiesz je tylko w razie potrzeby (!). Użyj profilerów, aby wskazać wąskie gardła i przepisać je w zewnętrzny sposób "C" , aby osiągnąć prędkość C. (Jeśli nadal wolno zaimplementuj tę część w ASM)
Rozmiar binarny. Kody C ++ są większe, ale tutaj jest świetna odpowiedź, która wyjaśnia szczegóły. Rozmiar skompilowanego pliku binarnego danego kodu C będzie taki sam, niezależnie od tego, czy został skompilowany przy użyciu kompilatora C czy C ++. „Rozmiar pliku wykonywalnego nie jest prawie związany z językiem, ale z bibliotekami, które dołączasz do projektu”. Przejść z C ++, ale uniknąć zaawansowane funkcje, jak
streams
,string
,new
,virtual
funkcje itp przeglądu wszystkich funkcji biblioteki przed pozwalając im w ostatecznym kodzie, ze względu na ograniczenia wielkości (na podstawie tej odpowiedzi)źródło