Włączyłem rzutowanie po prostu, aby pokazać dezaprobatę dla brzydkiej dziury w systemie tekstowym, co pozwala kompilować kod, taki jak poniższy fragment kodu, bez diagnostyki, mimo że żadne rzutowania nie są używane do spowodowania złej konwersji:
double d;
void *p = &d;
int *q = p;
Chciałbym, żeby to nie istniało (i nie ma w C ++), więc rzuciłem. Reprezentuje mój gust i moją politykę programistyczną. Nie tylko rzucam wskaźnik, ale skutecznie, rzucam kartę do głosowania i wyrzucam demony głupoty . Jeśli nie mogę tak naprawdę wyrzucić głupoty , to przynajmniej pozwólcie mi wyrazić życzenie gestem protestu.
W rzeczywistości dobrą praktyką jest owijanie malloc
(i znajomych) funkcjami, które zwracają unsigned char *
, i zasadniczo nigdy nie należy ich używać void *
w kodzie. Jeśli potrzebujesz ogólnego wskaźnika do dowolnego obiektu, użyj a char *
lub unsigned char *
i rzutuj w obu kierunkach. Jedną z relaksacji, na którą można sobie pozwolić, może być używanie funkcji takich jak memset
i memcpy
bez rzutów.
Na temat odlewów i kompatybilności C ++, jeśli napisać kod tak, że kompiluje jako ++ (w takim przypadku zarówno C i C muszą rzutować wartości zwracanej malloc
podczas przypisywania go do czegoś innego niż void *
), można zrobić bardzo pomocny rzecz dla siebie: możesz używać makr do rzutowania, które tłumaczą rzutowania w stylu C ++ podczas kompilacji jako C ++, ale redukują się do rzutowania C podczas kompilacji jako C:
/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif
Jeśli zastosujesz się do tych makr, proste grep
przeszukanie bazy kodu dla tych identyfikatorów pokaże Ci, gdzie znajdują się wszystkie Twoje rzutowania, dzięki czemu możesz sprawdzić, czy któryś z nich jest niepoprawny.
Następnie, jeśli będziesz regularnie kompilować kod w C ++, wymusi to użycie odpowiedniej obsady. Na przykład, jeśli używasz strip_qual
tylko w celu usunięcia const
lub volatile
, ale zmiany programu w taki sposób, że konwersja typu jest obecnie zaangażowany, dostaniesz diagnostyczny i trzeba będzie użyć kombinacji odlewów, aby uzyskać żądaną konwersję.
Aby pomóc Ci w przestrzeganiu tych makr, kompilator GNU C ++ (nie C!) Ma piękną funkcję: opcjonalną diagnostykę, która jest generowana dla wszystkich wystąpień rzutowań w stylu C.
-Old-style-cast (tylko C ++ i Objective-C ++)
Ostrzegaj, jeśli zostanie użyty rzut w starym stylu (w stylu C) na typ nieważny
w programie C ++. Odlewy w nowym stylu (dynamic_cast,
static_cast, reinterpret_cast i const_cast) są mniej wrażliwe
do niezamierzonych efektów i o wiele łatwiejsze do wyszukiwania.
Jeśli Twój kod C kompiluje się jako C ++, możesz użyć tej -Wold-style-cast
opcji, aby znaleźć wszystkie wystąpienia (type)
składni rzutowania, które mogą wkraść się do kodu, i śledzić tę diagnostykę, zastępując go odpowiednim wyborem spośród powyższych makr (lub połączenie, jeśli to konieczne).
Takie traktowanie konwersji jest największym pojedynczym samodzielnym technicznym uzasadnieniem pracy w „Clean C”: połączonym dialekcie C i C ++, co z kolei technicznie uzasadnia rzutowanie wartości zwracanej malloc
.