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 szczyt main()
jest już za późno.