Dlaczego C dominuje na rynku oprogramowania wbudowanego? [Zamknięte]

14

Prawie wszyscy powiedzą teraz błogosławieństwo:

wydajność !

Dobra, C pozwala na pisanie kodu sportowego. Ale przecież istnieją inne języki! A optymalizacja mocy nowoczesnych kompilatorów jest niesamowita. Czy C ma jakieś zalety, których nie ma żaden inny język? A może po prostu nie potrzebujesz bardziej elastycznych instrumentów w tej dziedzinie?

winorośl
źródło
1
FWIW, Arduino można kontrolować za pomocą C #: arduino.cc/playground/Interfacing/Csharp
FrustratedWithFormsDesigner
@Frustrated: Tak, ale to jest jeden przykład, a większość osób budujących urządzenia używa Arduino.
Ed S.
2
Zobacz także: stackoverflow.com/questions/812717/…
Steve Melnikoff,
1
@ dan04, w zdecydowanej większości przypadków to nie był problem. Grupa symulacyjna 6DOF z Texas Instruments Defense Systems and Electronics Group przeprowadziła mały eksperyment około 1988 roku. Do tego czasu przeprowadzali wszystkie symulacje w FORTRAN. Próbowali napisać jeden w PASCAL, aby zobaczyć, jak bardzo to boli. Odkryli, że PASCAL dał im niewielki hit wydajności, ale wzrost niezawodności i łatwości debugowania WIĘCEJ niż to zrekompensował. Bez ogródek stwierdzili, że sprawdzanie typu PASCAL-a było DOBRE. (I tak, robili tablice).
John R. Strohm

Odpowiedzi:

41

Prawie wszyscy powiedzą teraz błogosławieństwo:

występ!

To część tego; deterministyczne wykorzystanie zasobów jest ważne na urządzeniach z ograniczonymi zasobami na początek, ale są też inne powody.

  1. Bezpośredni dostęp do sprzętowych interfejsów API niskiego poziomu.
  2. Możesz znaleźć kompilator C dla zdecydowanej większości tych urządzeń. Z mojego doświadczenia nie dotyczy to żadnego języka wysokiego poziomu.
  3. C (środowisko wykonawcze i wygenerowany plik wykonywalny) jest „mały”. Nie musisz ładować do systemu wielu rzeczy, aby uruchomić kod.
  4. Sprzętowy interfejs API / sterowniki będą prawdopodobnie napisane w C lub C ++.
Ed S.
źródło
14
+1 Dostępność kompilatorów. Kiedy pisaliśmy wszystko w asemblerze, kompilatory pierwszej generacji były wysyłane przez Boga.
Christopher Bibbs,
8
+1, myślę, że deterministyczne wykorzystanie zasobów jest jednym z najważniejszych powodów. Nie masz dużo pamięci, aby robić wszelkiego rodzaju fantazyjne śmieci w zmywarce.
user281377
4
+1 również za „deterministyczne wykorzystanie zasobów”. W wielu systemach wbudowanych wymóg ten wyklucza nawet stosowanie dynamicznej alokacji pamięci. Wiele innych języków polega w dużej mierze na dynamicznej alokacji pamięci (nawet wiele korzystnych aspektów C ++ wymaga pamięci dynamicznej).
Michael Burr,
2
Dodam jeszcze jeden punkt, który okazuje się być raczej społeczny niż techniczny - myślę, że twórcy oprogramowania wbudowanego są o wiele bardziej konserwatywni i odporni na zmiany niż inni programiści. W zależności od twojego punktu widzenia może to być dobra lub zła rzecz.
Michael Burr,
1
Mówiąc jako facet od systemów, jestem ostrożny z dużymi abstrakcjami. Są świetne, dopóki nie przestaną działać lub nie zrobią czegoś śmiesznego. W takim przypadku debugowanie może być ogromnym bólem głowy. Nie chcę tego w systemie niskiego poziomu.
Ed S.
18

C został zaprojektowany do modelowania procesora, ponieważ C został stworzony, aby Unix był przenośny na różnych platformach, a nie tylko pisał asembler.

Oznacza to, że programy C działają dobrze jako język programowania dla programów, które muszą mieć poziom abstrakcji bardzo zbliżony do rzeczywistego procesora, co ma miejsce w przypadku wbudowanego sprzętu.

Uwaga: C został zaprojektowany około 1970 roku, a procesory były wtedy prostsze.


źródło
3
+1: Jest to zdecydowanie powód. Być może ludzie próbowali zaprojektować nowsze języki wysokiego poziomu, które wychwytują cechy współczesnych procesorów, ale nikt nie zaprojektował języka, który byłby przyłapany.
Ken Bloom
2
@ vines, C to mały język z dużą biblioteką środowiska wykonawczego. Wszystko to można zrobić w bibliotece wykonawczej. Po prostu nie migruje automatycznie do standardowej biblioteki C, więc jest specyficzna dla platformy.
3
+1. C został stworzony dla i początkowo używany na PDP-7, który miał maksymalnie 64 słów 18-bitowych słów. Wiele innych „nowoczesnych” języków ma większe trudności z dopasowaniem się do tego rodzaju przestrzeni. Zwłaszcza do pisania systemu operacyjnego takiego jak Unix.
greyfade
2
@greyfade: nie tak. UNIX powstał na PDP-7, ale C nie. Cytat ze wstępu do The C Programming Language : „C został pierwotnie zaprojektowany i wdrożony w systemie operacyjnym UNIX na DEC PDP-11 przez Dennisa Ritchiego.”
Jerry Coffin
1
@ vines: choć z pewnością rozsądne jest rozważenie bezpośredniego wsparcia wątków w języku (por. Concurrent C), duża część pamięci podręcznej polega na tym, że przyspiesza to bez jakiejkolwiek interwencji programisty lub języka.
Jerry Coffin
11

Jednym z powodów dominacji jest to, że ma odpowiednie narzędzia do tego zadania. Po opracowaniu na platformach osadzonych zarówno w Javie, jak i C / C ++, mogę powiedzieć, że podejście C ++ od podstaw do kości jest po prostu bardziej naturalne. Uratowanie programisty od poczucia, że ​​przeskakuje on przez obręcze, ponieważ poziom języka jest zbyt wysoki, jest dość irytujące. Dobrym przykładem jest brak niepodpisanych zmiennych w Javie.

Przydatne funkcje języka VM / języków interpretowanych są zwykle niewykonalne i nie są wdrażane, np. Garbage collection.

celebdor
źródło
3
„zarówno Java, jak i C / C ++” - mam nadzieję, że miałeś na myśli „wszystkie trzy: Java C i C ++”, ponieważ C i C ++ są różnymi językami.
BЈовић
1
@ BЈовић: Odpowiadając lata później, aby potwierdzić, że tak, miałem na myśli wszystkie trzy. Obaj zastosowałem tę definicję: „użyty jako słowo funkcyjne do wskazania i podkreślenia włączenia każdej z dwóch lub więcej rzeczy” (dwie lub więcej rzeczy) :-)
celebdor
10

C wymaga samo w sobie bardzo niewielkiego wsparcia w czasie wykonywania, więc narzut jest znacznie niższy. Nie poświęcasz pamięci ani miejsca na obsługę środowiska wykonawczego, nie spędzasz czasu / wysiłku, aby zminimalizować to wsparcie, ani nie musisz na to pozwalać w projekcie.

geekozaur
źródło
1
Czy tak naprawdę nigdy nie zdarza się, że potrzebujesz tej funkcjonalności i wymyślasz ją na nowo? Na przykład duże maszyny stanowe zbudowane z switches są straszne, a te same maszyny zbudowane z hierarchii klas są ładne i łatwe w utrzymaniu.
winorośl
1
@ vines - zwykle masz zdefiniowany zestaw danych wejściowych, maszyny stanowe zbudowane na przełączniku / jeśli drabiny są wyraźniejsze i bardziej udokumentowane niż dziedziczenie magii „polimorficznych wywołań za kulisami”.
Martin Beckett,
2
@Martin: dla kogoś z małym doświadczeniem w tworzeniu OO, wywołania polimorficzne nie są ani „magiczne”, ani „za kulisami”, a przekonanie, że ogromne zmiany / instrukcje są wyraźniejsze i bardziej dokumentowalne, wydaje się zupełnie dziwne.
Michael Borgwardt,
3
Znajdź, co się stanie, gdy pin27 osiągnie stan wysoki. Opcja 1, wyszukaj „przypadek PIN27:” Opcja 2 śledzi iterator nad mapą funktorów, aby dowiedzieć się, który z nich będzie wywoływany dla obiektów PIN przypisanych do pinu 27 w czasie wykonywania. Problem z dużą ilością kodu OO polega na tym, że jedynym sposobem na jego odczytanie jest jego uruchomienie. Na platformie bez debugowania w czasie wykonywania, a nawet na konsoli, co oznacza śledzenie kodu na papierze lub w głowie.
Martin Beckett,
2
Nieco styczna do tej dyskusji, istnieje powód, dla którego logika drabinkowa (nawet bardziej prymitywna wersja switch, można powiedzieć) jest nadal używana w wielu aplikacjach osadzonych. Łatwiejszy debugowanie, łatwiejszy do weryfikacji.
geekozaur
9

Jak wspomniano w innych odpowiedziach, C został opracowany na początku lat siedemdziesiątych, aby zastąpić język asemblera w architekturze minikomputera. W tamtych czasach komputery te zazwyczaj kosztowały dziesiątki tysięcy dolarów, w tym pamięć i urządzenia peryferyjne.

Obecnie możesz uzyskać taką samą lub większą moc komputera dzięki wbudowanemu 16-bitowemu mikrokontrolerowi, który kosztuje cztery dolary lub mniej w pojedynczych ilościach - w tym wbudowaną pamięć RAM i kontrolery I / O. 32-bitowy mikrokontroler kosztuje może dolara lub dwa więcej.

Kiedy programuję tych małych facetów, co robię w 90% przypadków, gdy nie projektuję płyt, na których siedzą, lubię wizualizować, co będzie robił procesor. Gdybym mógł wystarczająco szybko programować w asemblerze, zrobiłbym to.

Nie chcę wszelkiego rodzaju warstw abstrakcji. Często debuguję, przechodząc przez listę dissemblera na ekranie. O wiele łatwiej jest to zrobić, gdy na początku napisałeś program w C.

tcrosley
źródło
1
W przypadku niektórych aplikacji osadzonych „dolar lub dwa dodatkowe” jest bardzo znaczący. Nikt nie zauważy wpływu ceny na samochód, ale na termostacie lub odtwarzaczu CD.
David Thornley,
3
@David Thornley, tak, zgadzam się całkowicie, dlatego obecnie mam projekty z 8, 16 i 32-bitowymi mikrami jednocześnie dla różnych klientów. (Zużycie energii to kolejny powód, dla którego
warto
1
Cena zależy mniej od kosztu procesora niż liczby pinów. Tablice są znacznie droższe niż żetony.
Yttrill,
7

Nie do końca dominuje, ponieważ coraz częściej używa się C ++, ponieważ kompilatory uległy poprawie, a wydajność sprzętu wzrosła. Jednak C jest nadal bardzo popularny z kilku powodów;

  1. Szerokie wsparcie. Prawie każdy sprzedawca chipów zapewnia kompilator ac, a każdy przykładowy kod i sterowniki będą prawdopodobnie napisane w c. Kompilatory C ++ są coraz bardziej powszechne, ale nie są martwym certyfikatem dla danego układu i często są błędne. Wiesz również, że każdy inżynier wbudowany będzie mógł pracować w c. To lingua franca w branży.

  2. Występ. Tak, powiedziałeś to. Wydajność jest nadal najważniejsza, aw środowisku, w którym podstawowe procedury są często zapisywane w asemblerze lub przynajmniej zoptymalizowane w odniesieniu do danych wyjściowych asemblera, nigdy nie lekceważą tego znaczenia. Często osadzone cele będą bardzo tanie i będą miały bardzo małe wspomnienia i kilka mipsów.

  3. Rozmiar. C ++ jest zwykle większy. Z pewnością wszystko, co używa STL, będzie większe. Zasadniczo zarówno pod względem wielkości programu, jak i wielkości pamięci.

  4. Konserwatyzm. To bardzo konserwatywny przemysł. Częściowo dlatego, że koszty awarii są często wyższe, a debugowanie jest często mniej dostępne, częściowo dlatego, że nie trzeba go zmieniać. W przypadku małego osadzonego projektu c dobrze sobie radzi.

Luke Graham
źródło
11
Widzisz, jest to numer 3, który wydaje się być jednym z najbardziej rozpowszechnionych mitów na temat C ++. Napisz bezpieczny dla typu pojemnik dla 5 różnych typów w C, a będziesz powodował co najmniej tyle samo „wzdęć”, jak użycie jednego pojemnika STL na 5 różnych typach. Programiści C omijają ten problem, pisząc pojemniki na nieprzezroczystych typach (void *). Porównanie TO z szablonem STL jest błędem kategorii. Muszę jednak przyznać, że jest to rzeczywiście jeden z najczęstszych „powodów”, aby preferować C.
Edward Strange
Całkowicie się zgadzam, że replikacja pełnej funkcjonalności c kończy się tak samo jak c ++. „Zaletą” c jest to, że pozwala być selektywnym. W każdym znaczącym projekcie wolałbym używać c ++, ale czasami docelowy sprzęt jest ograniczony do punktu, w którym nie jest to praktyczne. Powiedziawszy, że # 1 jest naprawdę głównym powodem mojego doświadczenia.
Luke Graham,
6

W przypadku systemów wbudowanych najważniejsza jest wydajność . Ale tak jak powiedziałeś, dlaczego C, a nie jakiś inny wykonawczy język?

Jak dotąd wiele osób wspomniało o dostępności kompilatorów , ale nikt nie wspomniał o dostępności programistów . O wiele więcej programistów zna już C niż, powiedzmy, OCaml.

To są trzy duże.

BlueRaja - Danny Pflughoeft
źródło
6

Oprogramowanie wbudowane jest bardzo różne.

W aplikacji komputerowej abstrakcje i biblioteki oszczędzają dużo czasu na programowanie. Masz problem z rzuceniem kolejnej pary megabajtów lub gigabajtów pamięci RAM lub niektórych 64-bitowych rdzeni procesora 2 + GHz na problem, a ktoś inny (użytkownicy) płaci za ten sprzęt. Możesz nie wiedzieć, na jakich systemach aplikacja będzie działać.

W projekcie osadzonym zasoby są często bardzo ograniczone. W jednym projekcie, nad którym pracowałem (procesory z serii PIC 17X), sprzęt miał 2 słowa pamięci programu, 8 poziomów stosu (sprzętowego) i 192 bajty (<0,2 kB) pamięci RAM. Różne piny we / wy miały różne możliwości i skonfigurowałeś sprzęt w razie potrzeby, pisząc do rejestrów sprzętowych. Debugowanie obejmuje oscyloskop i analizator logiki.

W osadzonych abstrakcjach często przeszkadza i zarządza (i kosztuje) zasoby, których nie masz. Np. Większość systemów osadzonych nie ma systemu plików. Kuchenki mikrofalowe to systemy wbudowane. Sterowniki silnika samochodowego. Niektóre elektryczne szczoteczki do zębów. Niektóre słuchawki z redukcją szumów.

Jednym z bardzo ważnych dla mnie czynników przy tworzeniu systemów wbudowanych jest znajomość i kontrolowanie tego, co kod przekłada się na instrukcje, zasoby, pamięć i czas wykonania. Często dokładna sekwencja instrukcji steruje np. Synchronizacją przebiegów interfejsów sprzętowych.

Abstrakcje i „magia” za kulisami (np. Śmieci) jest świetna do aplikacji komputerowych. Śmieciarki oszczędzają dużo czasu, ścigając wycieki pamięci, gdy pamięć jest / może być dynamicznie przydzielana.

Jednak w świecie osadzonym w czasie rzeczywistym musimy wiedzieć i kontrolować, jak długo to trwa, czasem nawet do nanosekund, i nie możemy rzucić kolejnego megabajta pamięci RAM lub szybszego procesora na problem. Jeden prosty przykład: przy programowym przyciemnianiu diod LED przez kontrolowanie cyklu pracy (CPU miał tylko kontrolę włączania / wyłączania diod LED), NIE jest OK, aby procesor zgasł i wykonał np. Usuwanie śmieci na 100 ms, ponieważ wyświetlacz byłby widoczny błyskaj jasno lub gaśnie.

Bardziej hipotetycznym przykładem jest sterownik silnika, który bezpośrednio odpala świece zapłonowe. Jeśli ten procesor się wyłączy i zbierze śmieci na 50 ms, silnik wyłączyłby się na chwilę lub uruchomiłby niewłaściwe położenie wału korbowego, potencjalnie blokując silnik (podczas przejeżdżania?) Lub uszkadzając go mechanicznie. Możesz kogoś zabić.

Technofil
źródło
Jest to tak samo prawdziwe, jak nie ma znaczenia dla C - problem, o którym mówisz, dotyczy tylko zachowania GC ... C ++ nie ma żadnych GC i wiesz co? Osobiście używam go z uwagi na komentarze liniowe i bardziej rygorystyczne bezpieczeństwo =)
vines