C++: mity i fakty

W latach 90. rozpowszechniła się w kręgach zainteresowanych tematyką opinia, że język C++ nie nadaje się do tego, żeby pisać w nim programy dla mikrokontrolerów jednoukładowych. W przypadku małych systemów 8- i 16-bitowych, dominujących w tamtym okresie, jest to zapewne prawda. Ale dziś, w dobie tanich mikroprocesorów 32-bitowych o wielkiej (w porównaniu do tych z poprzednich dekad) mocy przetwarzania i znacznych zasobach, można sobie zadać pytanie, na ile ta niezbyt pochlebna dla C++ opinia ma nadal pokrycie w faktach, a na ile jest utrzymującym się siłą inercji mitem.

Posłuchaj
00:00
Spis treści

Wyjątki

Wyjątki mają na celu obsługę sytuacji nienormalnych, zatem implementacje kładą nacisk na poprawienie efektywności programu w sytuacjach "normalnych", to jest wtedy, kiedy stan wyjątkowy nie występuje. Czas obsługi stanu wyjątkowego - jak to się często podkreśla w różnych źródłach - może być trudny do przewidzenia, a to z dwóch powodów: po pierwsze dlatego, że optymalizacja pod kątem sprawnej obsługi sytuacji normalnych jest często dokonywana kosztem większego obciążenia obsługi stanu wyjątkowego; po drugie, w grę wchodzi trudna do oceny liczba i czas wykonywania wszystkich destruktorów wywoływanych podczas obsługi stanu wyjątkowego.

Użycie wyjątków powoduje także powiększenie programu: kompilator musi do niego dodać zestaw tablic sterujących wykonaniem wspomnianych destruktorów oraz zawierających adresy procedur obsługi poszczególnych wyjątków. Z tego powodu wiele kompilatorów oferuje opcję wyłączenia tego wszystkiego: eliminuje to wszelkie koszty związane z wyjątkami (oraz, oczywiście, wszelkie związane z nimi korzyści).

Przykład użycia wyjątku:

#include <iostream>
using namespace std;
int silnia(int n) throw(const char*)
{
if (n<0)
throw "ujemny parametr";
if (n>0)
return n*silnia(n-1);
return 1;
}
int main()
{
try
{
int n = silnia(10);
cout << "silnia(10)=" << n;
}
catch (const char* s)
{
cout << "błąd silni: " << s << "n";
}
return 0;
}

Poniżej mamy odpowiednik w języku C:

#include <stdio.h>
#include <setjmp.h>
jmp _ buf Exception;
const char *ExceptionValue;
int silnia(int n)
{
if (n<0)
{
ExceptionValue = "ujemny parametr";
longjmp(Exception, 0);
}
if (n>0)
return n*silnia(n-1);
return 1;
}
int main()
{
if (setjmp(Exception)==0)
{
int n = silnia(10);
printf("silnia(10)=%d", n);
}
else
{
printf("błąd silni: %sn",
ExceptionValue);
}
return 0;
}

Jest tu kilka problemów: przede wszystkim, program w języku C używa zmiennych globalnych. Z tego powodu longjmp() może zostać omyłkowo wywołane jeszcze przed własnym zainicjowaniem albo już po powrocie z funkcji main(). Poza tym programista musi ręcznie wywołać wszystkie odpowiedniki destruktorów przed wywołaniem longjmp() - a jeśli tego przez zapomnienie nie zrobi, nie istnieje mechanizm, który pozwoliłby kompilatorowi wykryć tego typu pomyłkę.

We wszystkich poprzednich przykładach można było liczyć na to, że dla konkretnych konstrukcji C++ istnieją mniej lub bardziej praktyczne odpowiedniki w języku C. Ale symulacja wyjątków daje tyle okazji do popełnienia dodatkowych błędów oraz, ogólniej, tak komplikuje kod źródłowy, że trudno to uznać za odpowiednik szczególnie praktyczny.

Powiązane treści
PRQA wprowadza narzędzie do analizy statycznej QA·C++ w nowej wersji V3.2
Zobacz więcej w kategorii: Technika
Komunikacja
Konserwacja predykcyjna w oparciu o uczenie maszynowe i IIoT
Zasilanie
Kryteria wyboru konwertera DC-DC do aplikacji medycznych
Optoelektronika
Inteligentne wyświetlacze firmy DWIN w ofercie Unisystemu
Komunikacja
Dzięki PCIe samochód przyszłości staje się rzeczywistością
Mikrokontrolery i IoT
Ataki na układy scalone
Projektowanie i badania
Izolacja w systemie akwizycji danych - zapewnia wysoką wydajność i doskonałe parametry
Zobacz więcej z tagiem: Artykuły
Statyczne
Logowanie
Targi krajowe
Warsaw Industry Week 2025 - 9. edycja
Targi krajowe
Targi przemysłowe SYMAS & MAINTENANCE
Zapytania ofertowe
Unikalny branżowy system komunikacji B2B Znajdź produkty i usługi, których potrzebujesz Katalog ponad 7000 firm i 60 tys. produktów