Często zadawane pytanie tutaj i gdzie indziej. Czy C ++ jest odpowiedni dla systemów wbudowanych?
Mikrokontrolery? RTOS? Tostery? Komputery wbudowane?
Czy OOP jest użyteczny w mikrokontrolerach?
Czy C ++ usuwa programator zbyt daleko od sprzętu, aby był wydajny?
Czy Cdu Arduino (bez dynamicznego zarządzania pamięcią, szablonów, wyjątków) powinien być uważany za „prawdziwy C ++”?
(Mam nadzieję, że ta wiki będzie służyć jako miejsce do powstrzymania tej potencjalnej świętej wojny)
microcontroller
embedded
programming
c++
Toby Jaffey
źródło
źródło
Odpowiedzi:
Tak, C ++ jest nadal użyteczny w systemach wbudowanych. Jak wszyscy powiedzieli, nadal zależy to od samego systemu, tak jak 8-bitowy interfejs użytkownika prawdopodobnie nie dałby mi żadnej książki, mimo że jest tam kompilator i niektórzy to robią (wzdrygają się). Korzystanie z C ++ jest nadal zaletą, nawet jeśli zmniejszysz go do czegoś takiego jak „C +”, nawet w 8-bitowym świecie mikro. Co mam na myśli przez „C +”? Mam na myśli: nie używaj nowych / usuń, unikaj wyjątków, unikaj wirtualnych klas z dziedziczeniem, ewentualnie unikaj dziedziczenia razem, bądź bardzo ostrożny z szablonami, używaj funkcji wbudowanych zamiast makr i używaj
const
zmiennych zamiast#defines
.Pracuję zarówno w C, jak i C ++ w systemach wbudowanych od ponad dekady, a część mojego młodego entuzjazmu dla C ++ zdecydowanie się skończyła z powodu problemów w świecie rzeczywistym, które wstrząsają naiwnością. Widziałem najgorsze C ++ w systemach wbudowanych, które chciałbym nazwać „programiści CS oszaleli w świecie EE”. W rzeczywistości nad tym pracuję z moim klientem, aby ulepszyć tę jedną bazę kodów, którą mają między innymi.
Niebezpieczeństwo związane z C ++ polega na tym, że jest to bardzo potężne narzędzie, podobnie jak miecz obosieczny, który może odciąć zarówno rękę, jak i nogę, jeśli nie jest odpowiednio wykształcony i zdyscyplinowany w swoim języku i samym programowaniu. C jest bardziej jak miecz obosieczny, ale wciąż równie ostry. W C ++ zbyt łatwo jest uzyskać bardzo wysoki poziom abstrakcji i tworzyć zaciemnione interfejsy, które stają się bez znaczenia w dłuższej perspektywie, a częściowo jest to spowodowane elastycznością C ++ w rozwiązywaniu tego samego problemu z wieloma różnymi funkcjami językowymi (szablony, OOP, procedury, Szablony RTTI, OOP +, przeciążanie, wstawianie).
Ukończyłem dwa 4-godzinne seminaria na temat oprogramowania wbudowanego w C ++ prowadzone przez guru C ++, Scotta Meyersa. Wskazał kilka rzeczy na temat szablonów, których nigdy wcześniej nie brałem pod uwagę, oraz o ile bardziej mogą one pomóc w tworzeniu krytycznego dla bezpieczeństwa kodu. Najważniejsze jest to, że nie można mieć martwego kodu w oprogramowaniu, które musi spełniać rygorystyczne wymagania dotyczące bezpieczeństwa. Szablony mogą ci w tym pomóc, ponieważ kompilator tworzy tylko potrzebny kod podczas tworzenia szablonów. Jednak należy lepiej poznać ich zastosowanie do prawidłowego projektowania tej funkcji, co jest trudniejsze do osiągnięcia w C, ponieważ linkery nie zawsze optymalizują martwy kod.
Scott Meyers jest bardzo wielkim zwolennikiem szablonów i rozsądnego korzystania z inliningu, i muszę powiedzieć, że nadal jestem sceptyczny wobec tego, że jestem ostrożny w kwestii szablonów. Mam tendencję do unikania ich, chociaż mówi, że powinny być stosowane tylko tam, gdzie stają się najlepszym narzędziem. Wskazuje również, że C ++ daje narzędzia do tworzenia naprawdę dobrych interfejsów, które są łatwe w użyciu i utrudniają niewłaściwe użycie. Ponownie, to jest najtrudniejsza część. Trzeba przejść do poziomu biegłości w C ++, zanim będziesz mógł wiedzieć, jak stosować te funkcje w najbardziej efektywny sposób, aby być najlepszym rozwiązaniem projektowym.
To samo dotyczy OOP. W świecie osadzonym musisz zapoznać się z kodem, który kompilator wypluje, aby dowiedzieć się, czy możesz poradzić sobie z kosztami polimorfizmu w czasie wykonywania. Musisz także być gotów wykonać pomiary, aby udowodnić, że Twój projekt spełni wymagania dotyczące terminu. Czy ta nowa klasa InterruptManager spowoduje, że moje opóźnienie przerwań będzie zbyt długie? Istnieją inne formy polimorfizmu, które mogą lepiej pasować do twojego problemu, takie jak polimorfizm w czasie połączenia, który C może również robić, ale C ++ może to zrobić poprzez wzorzec projektowy Pimpl (nieprzezroczysty wskaźnik) .
Mówię to wszystko, że C ++ ma swoje miejsce w świecie osadzonym. Możesz nienawidzić tego, co chcesz, ale to nie odchodzi. Można go napisać w bardzo wydajny sposób, ale trudniej jest nauczyć się, jak robić to poprawnie niż w C. Może czasem działać lepiej niż C w rozwiązywaniu problemu i czasami wyrażać lepszy interfejs, ale znowu musisz kształć się i nie bój się uczyć.
źródło
C ++ jest absolutnie odpowiedni dla systemów wbudowanych. Teraz używam obecności / braku dobrych narzędzi programistycznych (lub ich braku) jako mojego głównego kryterium przy wyborze konkretnego mikroprocesora.
Obszary C ++, które są dobre w systemach wbudowanych, ponieważ mają niskie koszty zasobów:
OK obszary:
Obszary, z których nie należy korzystać, głównie z powodu narzutu w czasie wykonywania, który jest niedopuszczalny w małych systemach:
źródło
foo
wywołujebar
wewnątrz blokutry
/catch
ibar
tworzy niektóre obiekty i wywołaniaboz
, co generuje wyjątek, system musi jakoś wywołać destruktory dla obiektówbar
utworzonych przed przywróceniem kontrolifoo
. O ile wyjątki nie zostaną całkowicie wyłączone, niebar
będzie w stanie wiedzieć, czyboz
można je wyrzucić, i dlatego musi zawierać dodatkowy kod, aby umożliwić taką możliwość. Chciałbym zobaczyć odmianę C ++ z „sprawdzonymi wyjątkami”, aby sobie z tym poradzić; jeśli procedury, które mogłyby pozwolić na uniknięcie wyjątków ...add r15,r14,#2
zamiastmov r15,r14
; ujść przez wyjątkuldrhs r0,[r14] / add r15,r14,r0
. Zerowy koszt cyklu dla normalnego wyjścia i bez ograniczeń ramek stosu.Tak, C ++ jest z pewnością odpowiedni dla systemów wbudowanych. Najpierw wyjaśnijmy kilka nieporozumień na temat różnicy między C i C ++:
We wbudowanej mikro zawsze będziesz musiał ostrożnie używać języków wysokiego poziomu, jeśli martwisz się ograniczeniami czasowymi lub przestrzennymi. Na przykład wiele MCU nie radzi sobie dobrze ze wskaźnikami, a więc są bardzo nieefektywne podczas używania stosu. Oznacza to, że musisz uważać na przekazywanie zmiennych do funkcji, używanie tablic i wskaźników oraz rekurencję. Prosta linia C, taka jak:
może wygenerować około 4 stron instrukcji w zależności od charakteru tych zmiennych.
Kiedykolwiek używasz żadnej języku wysokiego poziomu, i jesteś zaniepokojony ograniczeniami czasu i przestrzeni, to trzeba wiedzieć, jak każdy cechą tego języka przekłada się na swojej instrukcji maszynowych MCU (przynajmniej każdą funkcję, której używasz). Dotyczy to C, C ++, Ada, cokolwiek. Prawdopodobnie wszystkie języki będą zawierały funkcje, które nie tłumaczą się skutecznie na małych MCU. Zawsze sprawdzaj listę dezasemblacji, aby upewnić się, że kompilator nie generuje ryz instrukcji dotyczących czegoś trywialnego.
Czy C nadaje się do wbudowanych MCU? Tak, o ile masz oko na wygenerowany kod.
Czy C ++ jest odpowiedni dla osadzonych MCU? Tak, o ile masz oko na wygenerowany kod.
Oto dlaczego uważam, że C ++ jest lepszy niż C nawet na 8-bitowych MCU: C ++ zapewnia ulepszoną obsługę:
Żadna z tych cech nie jest cięższa niż typowe cechy C.
Gdy przesuwasz się do 16 lub 32-bitowych jednostek MCU, wtedy sensowne staje się używanie cięższych funkcji C (stos, stos, wskaźniki, tablice, printf itp.) W ten sam sposób, na bardziej wydajnym MCU staje się właściwe używać cięższych funkcji C ++ (stos, stos, referencje, STL, nowy / usuń).
Więc nie ma potrzeby drżeć na myśl o C ++ na PIC16. Jeśli dobrze znasz swój język i MCU, będziesz wiedział, jak skutecznie używać ich obu razem.
źródło
a[i] = b[j] * c[k];
może wygenerować około 4 stron instrukcji w zależności od charakteru tych zmiennych”. Jeśli robi to MCU / kompilator, dzieje się tak dlatego, że używasz jakiegoś hobbystycznego procesora z garażu z lat 80.Zawsze uważam te debaty za interesujące. Nie tyle za intelektualną dyskusję na temat zalet i wad różnych dostępnych języków, ale dlatego, że zazwyczaj można ustalić czyjąś postawę na ten temat w oparciu o pracę / doświadczenie / obszar zainteresowania. To właśnie tam, z argumentami „przedwczesnej optymalizacji”, w których specjaliści CS i programiści cytują Knutha w lewo i prawo, a ci, którzy pracują w prawdziwym świecie, w którym liczy się wydajność, uważają, że wszyscy są szaleni (jestem członkiem tej ostatniej grupy Aby być uczciwym).
Na koniec dnia możesz opracować doskonałe oprogramowanie w C lub C ++ lub wstawić tutaj język . Wszystko sprowadza się do możliwości programisty, a nie języka. Bycie ekspertem w języku jest zwykle wymagane tylko wtedy, gdy wybrałeś niewłaściwy język na początku, a teraz musisz go wypaczać w celu rozwiązania problemu, w większości przypadków są to jedyne sytuacje, w których musisz zagłębić się w niejasne funkcje lub kompilator sztuczki, aby osiągnąć cel.
Często słyszę, jak ludzie rozpoczynają te argumenty: „Jestem ekspertem w języku X i bla bla”. Szczerze od razu zdyskredytuję tych ludzi, ponieważ moim zdaniem podeszli już do problemu z niewłaściwego punktu widzenia, a wszystko po nim jest skażone poprzez chęć użycia narzędzia do rozwiązania problemu i pokazania, jak „fajne” jest.
Tak często obserwuję, jak programiści najpierw wybierają zestaw narzędzi, a następnie próbuję zgiąć go do drugiego problemu, co jest całkowicie błędne i skutkuje bzdurnymi rozwiązaniami.
Jak wspomniałem w komentarzu do innej odpowiedzi, te wojny językowe często przekształcają się w argument, że język X pozwala programiście robić bardziej głupie rzeczy. Mimo że zabawne są do przeczytania, wszystkie te stwierdzenia naprawdę oznaczają, że masz problem z zatrudnieniem dobrych programistów i musisz bezpośrednio rozwiązać ten problem, zamiast próbować pomóc w tej sytuacji, nadal zatrudniając złych programistów i wybierając narzędzia, które mogą zrobić tak mało uszkodzenie jak to możliwe.
Moim zdaniem dobrzy programiści, niezależnie od tego, czy zajmują się tworzeniem oprogramowania, czy sprzętu, badają problem, projektują rozwiązanie i znajdują narzędzia, które pozwalają im wyrazić rozwiązanie w „najlepszy sposób”. Nie powinno mieć znaczenia, czy wymagane narzędzie jest czymś, z czego nigdy wcześniej nie korzystałeś, po tym, jak użyjesz 3-4 języków / narzędzi programistycznych w projektach, które wybierają nowe, powinno to mieć minimalny wpływ na twój czas programowania.
Oczywiście „najlepszy sposób” jest pojęciem subiektywnym i należy je również zdefiniować na etapie badań. Należy wziąć pod uwagę wiele problemów: wydajność, łatwość wyrażania, gęstość kodu itp. W zależności od danego problemu. Z tego powodu nie umieściłem konserwacji na tej liście, nie dbam o to, jaki język wybierzesz, jeśli wybrałeś odpowiednie narzędzie i poświęciłeś czas na zrozumienie problemu, który powinien pojawić się „za darmo”. Trudny w utrzymaniu kod jest często wynikiem wyboru niewłaściwego narzędzia lub złej struktury systemu, co powoduje brzydki, zepsuty bałagan, aby działał.
Twierdzenie, że jakikolwiek język jest „lepszy” niż jakikolwiek inny, jest głupie bez definiowania konkretnego problemu. Podejście obiektowe nie zawsze jest lepsze niż podejście funkcjonalne. Istnieją pewne problemy, które bardzo dobrze nadają się do paradygmatu projektowania obiektowego. Jest wiele takich osób. To samo można powiedzieć o wielu funkcjach językowych, z których ludzie wydają się lubić czerpać przyjemność.
Jeśli spędzasz ponad 20% swojego czasu na problemie z pisaniem kodu, prawdopodobnie produkujesz bardzo słaby system lub masz bardzo słabych programistów (lub nadal się uczysz). Powinieneś spędzać większość czasu z góry na schematowaniu problemu i określaniu, w jaki sposób różne elementy aplikacji wchodzą w interakcje. Umieszczenie grupy utalentowanych programistów w pokoju z tablicą znaczników i problemem do rozwiązania i powiedzenie im, że nie wolno im pisać żadnego kodu ani wybierać żadnych narzędzi, dopóki nie poczują się dobrze z całym systemem, aby zrobić więcej, aby poprawić jakość wydajność i szybkość rozwoju niż wybór jakiegokolwiek nowego, gorącego narzędzia, które gwarantuje skrócenie czasu rozwoju. (spójrz na rozwój scrum jako odniesienie przeciwnego bieguna do mojego argumentu)
Często niefortunną rzeczywistością jest to, że wiele firm może mierzyć wartość dewelopera tylko na podstawie liczby zapisanych wierszy lub widząc „namacalne wyniki”. Widzą 3 tygodnie w pokoju z tablicą jako utratę wydajności. Deweloperzy są często zmuszani do przechodzenia przez fazę „przemyślenia” lub są zmuszeni do korzystania z narzędzi określonych przez pewne problemy polityczne w firmie: „Brat mojego szefa pracuje dla IBM, abyśmy mogli korzystać tylko z ich narzędzi”, tego rodzaju śmieci . Albo, co gorsza, otrzymujesz stale zmieniający się zestaw wymagań od firmy, ponieważ nie są oni w stanie przeprowadzić odpowiednich badań rynku lub nie rozumieją wpływu zmian na cykl rozwoju.
Przepraszam, że jestem trochę nie na temat tego zdania, mam dość mocne opinie na ten temat.
źródło
Dowolny język może być odpowiedni dla systemu wbudowanego. Osadzony oznacza po prostu: część większego urządzenia, w przeciwieństwie do komputera bezpłatnego.
Pytanie ma większe znaczenie, gdy zostanie poproszony o (twardy) system czasu rzeczywistego lub ograniczonych zasobów .
W systemie czasu rzeczywistego C ++ jest jednym z najwyższych języków, który jest nadal odpowiedni przy programowaniu pod kątem ścisłych ograniczeń czasowych. Z wyjątkiem użycia sterty (operator wolny) nie ma żadnych konstrukcji, które mają nieokreślony czas wykonania, więc możesz przetestować, czy twój program spełnia wymagania dotyczące czasu, a przy większym doświadczeniu możesz nawet go przewidzieć. Oczywiście należy unikać korzystania ze stosów, chociaż nowy operator nadal może być wykorzystywany do jednorazowego przydziału. Konstrukty oferowane przez C ++ w stosunku do C można dobrze wykorzystać w systemie osadzonym: OO, wyjątki, szablony.
W przypadku systemów o bardzo ograniczonych zasobach (8-bitowe układy, mniej niż kilka Kb pamięci RAM, brak dostępnego stosu) pełny C ++ może być nieodpowiedni, chociaż może być nadal używany jako „lepszy C”.
Myślę, że to niefortunne, że Ada wydaje się być używana tylko w niektórych niszach. Na wiele sposobów jest to Pascal ++, ale bez ciężaru bycia w górę kompatybilnym z językiem, który był już poważnym bałaganem na początek. (edytuj: poważny bałagan to oczywiście C. Pascal to piękny, ale nieco niepraktyczny język).
================================================== ==============
EDYCJA: Pisałem odpowiedź na nowe pytanie („W jakich przypadkach C ++ jest konieczne, gdy programujemy mikrokontrolery”?), Które zostało zamknięte w odniesieniu do tego, więc dodam to, co napisałem:
Nigdy nie ma nadrzędnego powodu do używania jakiegokolwiek języka programowania, ale mogą istnieć argumenty, które mają większą lub mniejszą wagę w konkretnej sytuacji. Dyskusje na ten temat można znaleźć w wielu miejscach, zajmując stanowiska w zakresie od „nigdy nie używaj C ++ do mikrokontrolera” do „zawsze używaj C ++”. Jestem bardziej z ostatnią pozycją. Mogę podać kilka argumentów, ale musisz sam zdecydować, ile wnoszą one w danej sytuacji (i w jakim kierunku).
Na moim blogu jest kilka artykułów na temat używania C ++ na małych systemach (= mikrokontrolery).
źródło
Z mojego doświadczenia wynika, że C ++ jest zwykle nieodpowiedni dla małych systemów osadzonych. Rozumiem przez to mikrokontrolery i urządzenia bez OS.
Wiele technik C ++ OOP opiera się na dynamicznej alokacji pamięci. Tego często brakuje w małych systemach.
STL i Boost naprawdę pokazują moc C ++, oba mają ogromne rozmiary.
C ++ zachęca programistę do wyodrębnienia maszyny, gdzie w ograniczonych systemach należy ją objąć.
W ubiegłym roku przeniosłem komercyjny produkt zdalnego pulpitu na telefony komórkowe. Został napisany w C ++ i działał na systemach Windows, Linux i OSX. Ale w dużej mierze opierał się na STL, pamięci dynamicznej i wyjątkach C ++. Aby działało w środowisku WinCE, Symbian i bez OS, przepisanie C było najrozsądniejszą opcją.
źródło
Mam nadzieję, że dodam więcej światła niż ciepła do dyskusji na temat C ++ w systemach bez systemu metalowego i zasobów.
Problemy w C ++:
Wyjątki stanowią w szczególności problem z pamięcią RAM, ponieważ wymagany „bufor awaryjny” (na przykład dotyczy wyjątku braku pamięci) może być większy niż dostępna pamięć RAM i z pewnością marnuje mikrokontrolery. Aby uzyskać więcej informacji, patrz n4049 i n4234 . Powinny być wyłączone (co jest obecnie nieokreślonym zachowaniem, więc bądź pewien i nigdy nie rzucaj). SG14 pracuje obecnie nad lepszymi sposobami na zrobienie tego.
RTTI prawdopodobnie nigdy nie jest warte narzutu, należy go wyłączyć
Duże kompilacje debugowania, chociaż nie jest to problem w klasycznym projektowaniu pulpitu, jeśli debugowanie nie mieści się w układzie, może to stanowić problem. Problem wynika z kodu szablonowego lub dodatkowych wywołań funkcji dodanych dla przejrzystości. Te dodatkowe funkcje zostaną ponownie usunięte przez optymalizator, a dodatkowa przejrzystość lub elastyczność może być wielką zaletą, jednak w kompilacjach debugowania może to stanowić problem.
Przydział stert. Chociaż STL pozwala na użycie niestandardowych alokatorów, może to być skomplikowane dla większości programistów. Alokacja sterty nie jest deterministyczna (tzn. Nie jest trudna w czasie rzeczywistym), a fragmentacja może prowadzić do nieoczekiwanych sytuacji braku pamięci, mimo że pracowała w testowaniu. Prowadzenie ksiąg przez stertę w celu śledzenia wolnej przestrzeni i różnych rozmiarów może być problemem dla małych obiektów. Zazwyczaj lepiej jest używać alokacji puli (zarówno w C, jak i C ++), ale może to być nieprawidłowe w przypadku programistów C ++, którzy używali tylko sterty.
Polimorfizm środowiska wykonawczego i inne wywołania pośrednie są zwykle dużym hitem wydajności, problem jest zwykle większy, ponieważ optymalizator nie widzi ich bardziej niż faktyczne pobieranie i przeskakiwanie do adresu. Z tego powodu należy unikać wywołań pośrednich w C i C ++, gdzie podobnie jak w C ++ są one bardziej zakorzenione w kulturze (i są całkiem przydatne w innych domenach).
niejawne połączenie z biblioteką Clib może być problematyczne. Może być sprzeczne z intuicją, że problemy z biblioteką znajdują się w kategorii C ++, ale problem wynika z niejawnego udostępniania zasobów w współbieżnych środowiskach (udostępnianie jest bardziej wyraźne w C). Korzystanie ze wspólnej implementacji newLib często powoduje wiele wzdęć, które zwykle nie są potrzebne w UC, z drugiej strony newLibNanno nie jest ponownie wysyłany, więc dostęp do niego musi zostać zserializowany (tutaj nadmierne uproszczenie). Jest to problem również dla C, ale dostęp jest bardziej wyraźny. Zasadniczo nie należy zasadniczo używać niczego z przestrzeni nazw std w kontekście ISR, chyba że masz pewność, że nie uzyska dostępu do stanu w bibliotece clib (na przykład errorno lub sterta). Jest to również ważne, jeśli używasz wątków (wolę RTC), aby zastąpić nowe i usunąć, aby zsynchronizować dostęp do malloc i za darmo.
Podsumowując, C ++ ma pewne problemy, ale zasadniczo można je naprawić lub uniknąć.
Teraz dla C, tutaj problemem jest wyższy porządek. Nie mam zdolności syntaktycznej w C do abstrakcyjnego tworzenia rzeczy w sposób umożliwiający mi optymalizację lub sprawdzanie niezmienników w czasie kompilacji. Dlatego nie mogę poprawnie hermetyzować rzeczy w taki sposób, że użytkownik nie musi wiedzieć, jak działają, aby z nich korzystać, a większość moich wykrywania błędów jest wykonywana w czasie wykonywania (co nie tylko jest za późno, ale także powoduje dodatkowe koszty). Zasadniczo jedynym sposobem, aby być ogólnym w C, są dane, przekazuję ciąg formatu do printf lub scanf, który jest oceniany na przykład w czasie wykonywania. Kompilatorowi trudno jest udowodnić, że nie korzystam z niektórych opcji, które teoretycznie są możliwe po przekazaniu odpowiednich danych, co oznacza potencjalne generowanie martwego kodu i utratę potencjału optymalizacyjnego.
Wiem, że mogę tutaj rozpętać burzę, ale moje doświadczenie z 32-bitowymi mikrokontrolerami polega na tym, że w porównaniu jabłek do jabłek porównanie C i C ++ zarówno napisanych przez ekspertów (jak w C ++ potencjalnie wysoce szablonowych) C ++ jest znacznie bardziej wydajnym językiem, gdy tylko wszystko musi być w ogóle ogólne (jak w każdej bibliotece) i są zasadniczo równoważne w przypadkach innych niż ogólne. Nowicjuszowi łatwiej jest również wykorzystać wiedzę eksperta w dziedzinie implementacji bibliotek w C ++.
Jednocześnie jest tak naprawdę naprawdę niewiele funkcji, do których nie mogę przekazać niepoprawnych danych, gdy tylko dane wejściowe nie są liczbą całkowitą, ale
something
dla której akurat używam liczby wewnętrznej jako metody reprezentacji, istnieje możliwość jej uzyskania niepoprawnie (przekaż niepoprawną wartość lub „inną rzecz” zamiast „czegoś”). W C moją jedyną metodą sprawdzenia, czy użytkownik nie pomylił się, jest w czasie wykonywania. W C ++ mam możliwość wykonywania niektórych kontroli, nie wszystkich kontroli, ale niektóre kontrole w czasie kompilacji, które są bezpłatne.Pod koniec dnia zespół C jest często tak potężny, jak jego najsłabszy programista, a korzyści wynikające z kodu wynikają z gry wieloosobowej równej 1 lub obniżenia wydajności. Rozumiem przez to, że jest to albo wysoka wydajność dla jednego i tylko jednego wyjątkowego zadania w unikalnym środowisku z unikalnymi decyzjami projektowymi, albo jest wystarczająco ogólna, aby można ją było stosować w wielu środowiskach (inny mikrokontroler, inna strategia zarządzania pamięcią, inne opóźnienie vs. kompromisy związane z wydajnością itp. itp.), ale wiąże się to z nieodłącznym kosztem wydajności.
W C ++ rzeczy mogą być enkapsulowane przez ekspertów i używane w wielu środowiskach, w których generowanie kodu czasowego dostosowuje się do konkretnego zadania, a sprawdzanie statyczne powstrzymuje użytkowników przed robieniem głupich rzeczy przy zerowym koszcie. Tutaj mamy znacznie mniejszy kompromis między byciem ogólnym a szybkim, a zatem ostatecznie z punktu widzenia kosztów i korzyści są bardziej wydajne, bezpieczniejsze i bardziej produktywne.
Jest to słuszna krytyka, że wciąż brakuje dobrych bibliotek C ++ do osadzania, może to prowadzić do pragmatycznych decyzji o używaniu głównie C na kompilatorze C ++. Decyzje o zastosowaniu tylko C w projekcie są zasadniczo albo motywowane ideologicznie, z potrzeby starszego wsparcia lub przyznania, że zespół nie jest wystarczająco zdyscyplinowany, aby powstrzymać się od bardzo wybranego zestawu głupich rzeczy, które można zrobić w C ++, ale nie w C i jednocześnie zdyscyplinowany na tyle, aby nie robić żadnego z głupszych rzeczy, przed którymi nie można się bronić w C, ale w C ++.
źródło
Moje pochodzenie: tuż po szkoleniu u starych programistów Bell Labs; pracuję od 3 lat, 2 nad studiami licencjackimi; akwizycja danych / kontrola procesu w VB.NET. Spędziłem 1,5 roku pracując nad aplikacją korporacyjnej bazy danych w VB6. Obecnie pracuje nad projektem dla wbudowanego komputera z 2 GB pamięci, 512 MB pamięci RAM, procesorem 500 MHz x86; kilka aplikacji działających jednocześnie w C ++ z mechanizmem IPC pomiędzy nimi. Tak, jestem młoda.
Moja opinia: Myślę, że C ++ może działać skutecznie w środowisku, które napisałem powyżej . Trzeba przyznać, że wydajność aplikacji w czasie rzeczywistym nie jest wymagana dla aplikacji, w której korzystam, aw niektórych aplikacjach wbudowanych może to stanowić problem. Ale oto rzeczy, których się nauczyłem:
C ++ zasadniczo różni się od C (tzn. Nie ma C / C ++). Podczas gdy wszystko, co jest poprawne, C jest poprawne C ++, C ++ jest bardzo innym językiem i trzeba nauczyć się programowania w C ++, a nie C, aby skutecznie używać go w każdej sytuacji. W C ++ musisz programować obiektowo, nie proceduralnie, a nie hybrydę dwóch (duże klasy z dużą ilością funkcji). Ogólnie rzecz biorąc, powinieneś skupić się na tworzeniu małych klas z kilkoma funkcjami i skomponować wszystkie małe klasy razem w większe rozwiązanie. Jeden z moich współpracowników wyjaśnił mi, że programowałem proceduralnie w obiektach, co jest wielkim bałaganem i jest trudne do utrzymania. Kiedy zacząłem stosować techniki bardziej obiektowe, zauważyłem, że mój kod / łatwość obsługi / odczytu wzrosła.
C ++ zapewnia dodatkowe funkcje w postaci programowania obiektowego, które mogą zapewnić sposób uproszczenia kodu, aby ułatwić czytanie / utrzymanie . Szczerze mówiąc, nie sądzę, że jest wiele na drodze do poprawy wydajności / wydajności przestrzeni w robieniu OOP. Ale myślę, że OOP to technika, która może pomóc w podzieleniu złożonego problemu na wiele małych kawałków. Jest to pomocne dla osób pracujących nad kodem, elementu tego procesu, którego nie należy ignorować.
Wiele argumentów przeciwko C ++ dotyczy przede wszystkim dynamicznej alokacji pamięci. C ma również ten sam problem. Możesz pisać aplikacje zorientowane obiektowo bez użycia pamięci dynamicznej, chociaż jedną z zalet korzystania z obiektów jest to, że możesz przydzielać te rzeczy dynamicznie w łatwy sposób. Podobnie jak w C, musisz uważać na sposób zarządzania danymi w celu zmniejszenia wycieków pamięci, ale technika RAII upraszcza to w C ++ (automatyczne niszczenie pamięci dynamicznej przez hermetyzację jej w obiektach). W niektórych aplikacjach, gdzie liczy się każda lokalizacja pamięci, może to być zbyt dzikie i wełniste, aby zarządzać.
EDYTOWAĆ:
źródło
Tak, problem z C ++ polega na zwiększonej powierzchni kodu.
W niektórych systemach liczysz bajty, w takim przypadku będziesz musiał zaakceptować koszt działania zbliżony do granic swoich systemów, to zwiększone koszty rozwoju C.
Ale nawet w C, dla dobrze zaprojektowanego systemu, musisz wszystko zamknąć. Dobrze zaprojektowane systemy są trudne, a C ++ daje programistom miejsce na bardzo ustrukturyzowaną i kontrolowaną metodę rozwoju. Nauka OOP wiąże się z pewnymi kosztami, a jeśli chcesz się na nią przełączyć, bardzo ją akceptujesz, aw wielu przypadkach zarząd wolałby kontynuować C i nie płacić kosztów, ponieważ trudno jest zmierzyć wyniki zmiany, która zwiększa wydajność. Artykuł autorstwa guru systemów osadzonych Jacka Ganssle'a można znaleźć tutaj .
Dynamiczne zarządzanie pamięcią to diabeł. Nie bardzo, diabeł ma automatyczną trasę, dynamiczne zarządzanie pamięcią działa świetnie na komputerze, ale możesz oczekiwać, że uruchomisz komputer co najmniej co kilka tygodni. Przekonasz się, że ponieważ system osadzony działa przez 5 lat, dynamiczne zarządzanie pamięcią może się naprawdę zepsuć i zacząć działać. Ganssle omawia w swoim artykule takie rzeczy, jak stos i stos.
W C ++ są pewne rzeczy, które są bardziej podatne na problemy i zużywają wiele zasobów, usuwanie dynamicznego zarządzania pamięcią i szablony to duże kroki, aby utrzymać ślad C ++ bliżej do śladu C. Jest to nadal C ++, nie potrzebujesz dynamiki zarządzanie pamięcią lub szablony do pisania dobrego C ++. Nie zdawałem sobie sprawy, że usunęli wyjątki, uważam wyjątki za ważną część mojego kodu, którą usuwam w wersji, ale używam do tego momentu. W testach terenowych mogę mieć generowane wyjątki, które informują mnie o przechwyceniu wyjątku.
źródło
Myślałem, że ten anty-C ++ rząd Linusa Torvaldsa był interesujący.
Nie mówi o świecie systemów osadzonych, ale o rozwoju jądra Linuksa. Dla mnie znaczenie ma to: C ++ wymaga zrozumienia szerszego kontekstu i mogę nauczyć się korzystać z zestawu szablonów obiektów, nie ufam sobie, że je zapamiętam, gdy muszę zaktualizować kod za kilka miesięcy.
(Z drugiej strony, obecnie pracuję na urządzeniu wbudowanym przy użyciu Pythona (nie C ++, ale przy użyciu tego samego paradygmatu OOP), który będzie miał dokładnie ten problem. W mojej obronie jest to system wbudowany wystarczająco silny, aby nazwać go PC 10 lat temu.)
źródło
Sądzę, że inne odpowiedzi stanowiły całkiem dobrą argumentację za plusami i minusami oraz czynnikami decyzyjnymi, dlatego chciałbym tylko podsumować i dodać kilka komentarzy.
Dla małych mikrokontrolerów (8-bitowych) nie ma mowy. Po prostu prosisz o zranienie siebie, nie ma zysku, a oddasz za dużo zasobów.
W przypadku wysokiej klasy mikrokontrolerów (np. 32-bitowych, 10 lub 100 MB pamięci RAM i pamięci masowej), które mają przyzwoity system operacyjny, jest to całkowicie OK i, śmiem powiedzieć, nawet zalecane.
Pytanie brzmi: gdzie jest granica?
Nie wiem na pewno, ale kiedy opracowałem system dla 16-bitowego interfejsu użytkownika z 1 MB pamięci RAM i 1 MB pamięci w C ++, żałuję tego później. Tak, działało, ale dodatkowa praca, którą miałem, nie była tego warta. Musiałem go dopasować, dopilnować, aby takie wyjątki nie powodowały wycieków (obsługa OS + RTL była dość błędna i zawodna). Co więcej, aplikacja OO zazwyczaj wykonuje wiele małych alokacji, a narzuty związane z nimi były kolejnym koszmarem.
Biorąc pod uwagę to doświadczenie, zakładam, że w przyszłych projektach wybiorę C ++ tylko w systemach co najmniej 16-bitowych i co najmniej 16 MB na pamięć RAM i pamięć. To arbitralny limit i prawdopodobnie będzie się różnić w zależności od rodzaju aplikacji, stylów kodowania i idiomów itp. Ale z zastrzeżeniem, zaleciłbym podobne podejście.
źródło
Niektóre funkcje C ++ są przydatne w systemach wbudowanych. Istnieją inne, na przykład wyjątki, które mogą być kosztowne i których koszty nie zawsze są oczywiste.
Gdybym miał moje druty, byłby popularny język, który łączyłby to, co najlepsze z obu światów, i zawierał pewne funkcje, których brakuje w obu językach; niektórzy dostawcy zawierają kilka takich funkcji, ale nie ma żadnych standardów. Kilka rzeczy, które chciałbym zobaczyć:
Wiem, że ojciec C ++ nie przepada za wbudowaną wersją C ++, ale sądzę, że może on zaoferować pewne znaczące ulepszenia w porównaniu do zwykłego używania C.
Czy ktoś wie, czy coś takiego jak wyżej jest rozważane dla jakiegokolwiek rodzaju standardu?
źródło
C ++ to więcej niż jeden język programowania:
a) To „lepszy” C b) To język zorientowany obiektowo c) To język, który pozwala nam pisać programy ogólne
Chociaż wszystkie te funkcje mogą być używane osobno, najlepsze wyniki osiąga się, gdy trzy z nich są używane jednocześnie. Niemniej jednak, jeśli wybierzesz tylko jedną z nich, jakość wbudowanego oprogramowania wzrośnie.
a) To „lepsze” C
C ++ jest silnie napisanym językiem; silniejszy niż C. Twoje programy skorzystają z tej funkcji.
Niektórzy boją się wskazówek. C ++ zawiera referencje. Przeciążone funkcje.
I warto powiedzieć: Żadna z tych funkcji nie pojawiła się w większych lub wolniejszych programach.
b) Jest to język obiektowy
Ktoś powiedział w tym poście, że abstrakcja maszyny w mikrokontrolerach nie jest dobrym pomysłem. Źle! Każdy z nas, inżynierów osadzonych, zawsze wyabstrahował maszynę, tylko z innym sintaxem niż C ++. Problem, który widzę w tym argumencie, polega na tym, że niektórzy programiści nie są przyzwyczajeni do myślenia w obiektach, w ten sposób nie widzą korzyści z OOP.
Ilekroć jesteś gotowy do korzystania z urządzenia peryferyjnego mikrokontrolera, jest prawdopodobne, że urządzenie peryferyjne zostało dla nas (od ciebie lub osoby trzeciej) wyodrębnione w formie sterownika urządzenia. Jak powiedziałem wcześniej, ten sterownik używa sintax C, jak pokazuje następny przykład (wzięty bezpośrednio z przykładu NXP LPC1114):
/ * Ustawienia timera dla dopasowania i przerwania w TICKRATE_HZ * /
Chip_TIMER_Reset (LPC_TIMER32_0);
Chip_TIMER_MatchEnableInt (LPC_TIMER32_0, 1);
Chip_TIMER_SetMatch (LPC_TIMER32_0, 1, (timerFreq / TICKRATE_HZ2));
Chip_TIMER_ResetOnMatchEnable (LPC_TIMER32_0, 1);
Chip_TIMER_Enable (LPC_TIMER32_0);
Czy widzisz abstrakcję? Tak więc, używając C ++ do tego samego celu, abstrakcja jest przenoszona na wyższy poziom dzięki mechanizmowi abstrakcji i enkapsulacji C ++, przy zerowym koszcie!
c) Jest to język, który pozwala nam pisać ogólne programy
Programy ogólne są realizowane za pomocą szablonów, a szablony również nie wiążą się z żadnymi kosztami dla naszych programów.
Poza tym za pomocą szablonów osiąga się statyczny polimorfizm.
Metody wirtualne, RTTI i wyjątki.
Podczas korzystania z metod wirtualnych istnieje kompromis: lepsze oprogramowanie vs. pewna obniżka wydajności. Pamiętaj jednak, że powiązanie dynamiczne prawdopodobnie zostanie zaimplementowane przy użyciu wirtualnej tabeli (tablicy wskaźników funkcji). Robiłem to samo w C wiele razy (nawet regularnie), więc nie widzę wad korzystania z metod wirtualnych. Ponadto metody wirtualne w C ++ są bardziej eleganckie.
Na koniec rada na temat RTTI i wyjątków: NIE UŻYWAJ ich w systemach wbudowanych. Unikaj ich za wszelką cenę !!
źródło
Moje tło, osadzone (MCU, PC, UNIX, inne), w czasie rzeczywistym. Bezpieczeństwo krytyczne. Przedstawiłem poprzedniego pracodawcę firmie STL. Już tego nie robię.
Trochę treści Flame
Czy C ++ jest odpowiedni dla systemów wbudowanych?
Meh C ++ jest trudny do napisania i trudny do utrzymania. C + jest w porządku (nie używaj niektórych funkcji)
C ++ w mikrokontrolerach? RTOS? Tostery? Komputery wbudowane?
Znowu mówię Meh. C + nie jest takie złe, ale ADA jest mniej bolesne (a to naprawdę coś mówi). Jeśli masz szczęście, tak jak ja, możesz zainstalować wbudowaną Javę. Sprawdzony dostęp do tablicy i brak arytmetyki wskaźnika zapewnia bardzo niezawodny kod. Garbage collectors in embedded Java nie mają najwyższego priorytetu, a zakres pamięci i ponownego użycia obiektów jest ograniczony, więc dobrze zaprojektowany kod może działać wiecznie bez GC.
Czy OOP jest użyteczny w mikrokontrolerach?
Jasne, że tak. UART jest obiektem ..... DMAC jest obiektem ...
Maszyny stanu obiektu są bardzo łatwe.
Czy C ++ usuwa programator zbyt daleko od sprzętu, aby był wydajny?
Chyba że jest to PDP-11, C nie jest twoim procesorem. C ++ był pierwotnie preprocesorem na C, więc Bjarne Stroustrup przestał się śmiać z powolnych symulacji Simula podczas AT&T. C ++ to nie twój procesor.
Idź dostać MCU, który uruchamia jatecodes bajtów. Program w Javie. Śmiej się z chłopaków z C.
Czy Cdu Arduino (bez dynamicznego zarządzania pamięcią, szablonów, wyjątków) należy uważać za „prawdziwe C ++”?
Nie. podobnie jak wszystkie drobne kompilatory C dostępne dla MCU.
Po drugie, Embedded Java lub Embedded ADA są znormalizowane (ish); wszystko inne to smutek.
źródło
Systemy wbudowane są zaprojektowane do wykonywania określonych zadań, a nie do komputerów ogólnego przeznaczenia do wykonywania wielu zadań. System osadzony to połączenie sprzętu komputerowego i oprogramowania. C jest matką wszystkich współczesnych języków. Jest to niski poziom, ale obsługuje pełny język i obsługuje wszelkiego rodzaju sprzęt. Tak więc C / C ++ jest optymalnym wyborem do tworzenia oprogramowania dla systemu wbudowanego, który jest bardzo przydatny dla każdego systemu wbudowanego. Jak wiemy, C jest językiem rozwijającym się. System operacyjny UNIX jest napisany w C. Ponieważ udane tworzenie oprogramowania tak często polega na wyborze najlepszego języka dla danego projektu, zaskakujące jest stwierdzenie, że język C / C ++ okazał się odpowiedni zarówno dla procesorów 8-bitowych, jak i 64-bitowych ; w systemach z bajtami, kilobajtami i megabajtami pamięci. Zaletą C jest niezależność procesora, co pozwala programistom skoncentrować się na algorytmach i aplikacjach, a nie na szczegółach dotyczących konkretnej architektury procesora. Jednak wiele z tych zalet dotyczy w równym stopniu innych języków wysokiego poziomu. Ale C / C ++ odniósł sukces tam, gdzie tak wiele innych języków w dużej mierze zawiodło?
źródło
<rant>
Myślę, że C ++ to przede wszystkim gówniany język. Jeśli chcesz korzystać z OOP, pisz programy Java. C ++ nie robi nic, by wymusić paradygmaty OOP, ponieważ bezpośredni dostęp do pamięci jest w pełni w twojej mocy do (ab) użycia.
Jeśli masz MCU, mówisz o najprawdopodobniej mniej niż 100 kB pamięci flash. Chcesz programować w języku, którego abstrakcją pamięci jest: kiedy deklaruję zmienną lub tablicę, dostaje pamięć, kropkę; malloc (inaczej „nowe” słowo kluczowe w C ++) powinno być mniej więcej zakazane w oprogramowaniu wbudowanym, z wyjątkiem być może w rzadkich przypadkach jednego połączenia podczas uruchamiania programu.
Do diabła, w programowaniu wbudowanym są (często) czasy, w których C nie jest wystarczająco niskiego poziomu, i musisz robić takie rzeczy, jak przydzielanie zmiennych do rejestrów i pisanie wbudowanego zestawu, aby zacieśnić swoje procedury obsługi przerwań (ISR). Słowa kluczowe takie jak „niestabilny” stają się naprawdę ważne, aby je zrozumieć. Dużo czasu spędzasz na manipulowaniu pamięcią na poziomie bitów , a nie na poziomie obiektu .
Dlaczego miałbyś oszukiwać się, myśląc, że rzeczy są prostsze niż w rzeczywistości?
</rant>
źródło