Jaka jest różnica między rzutowaniem static_cast <> a rzutowaniem w stylu C?

Odpowiedzi:

217

Rzutowania w stylu C ++ są sprawdzane przez kompilator. Rzutowania w stylu C nie są i mogą zawieść w czasie wykonywania.

Ponadto rzutowania w stylu c ++ mogą być łatwo wyszukiwane, podczas gdy naprawdę trudno jest znaleźć rzutowania w stylu c.

Kolejną dużą zaletą jest to, że 4 różne odlewy w stylu C ++ wyraźniej wyrażają zamiary programisty.

Pisząc C ++, prawie zawsze używam C ++ zamiast stylu C.

Dolina górska
źródło
67
Jedynymi rzutami, które mogą zakończyć się niepowodzeniem w czasie wykonywania, są dynamic_casts.
R. Martinho Fernandes
12
C ++ reinterpret_cast <T> (U) może zawieść w czasie wykonywania prawie tak samo jak rzutowania w stylu C, i wszystkie one są zupełnie różne od tego, jak zawodzi dynamiczny rzut_T> (U).
Christopher Smith
20
Normal1 normalne przesyłanie w C (int)somethingnie może zakończyć się niepowodzeniem - albo pojawi się błąd int lub błąd kompilatora.
Tomáš Zato - Przywróć Monikę
2
Czy możesz wyjaśnić, dlaczego odlewy C ++ można wyszukiwać łatwiej niż odlewy C?
Minh Tran
3
@MinhTran W stylu C ++ można wyszukać słowo kluczowe „obsada” poprzez pliki źródłowe. Ale czy mógłbyś zrobić z obsadami w stylu c?
huangzonghao
176

W skrócie :

  1. static_cast<>() daje możliwość sprawdzania czasu kompilacji, nie obsługuje rzutów w stylu C.
  2. static_cast<>() jest bardziej czytelny i można go łatwo zauważyć w dowolnym miejscu kodu źródłowego C ++, rzutowanie C_Style nie jest.
  3. Intencje są przekazywane znacznie lepiej przy użyciu rzutowań C ++.

Więcej wyjaśnień :

Obsada statyczna wykonuje konwersje między zgodnymi typami . Jest podobny do obsady w stylu C, ale jest bardziej restrykcyjny. Na przykład rzutowanie w stylu C umożliwia wskaźnikowi całkowitemu wskazywanie znaku.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Ponieważ skutkuje to 4-bajtowym wskaźnikiem (wskaźnikiem do 4-bajtowego typu danych) wskazującym na 1 bajt przydzielonej pamięci, zapis do tego wskaźnika spowoduje błąd w czasie wykonywania lub zastąpi przyległą pamięć.

*p = 5; // run-time error: stack corruption

W przeciwieństwie do rzutowania w stylu C, rzutowanie statyczne pozwoli kompilatorowi sprawdzić, czy typy danych wskaźnika i pointee są kompatybilne, co pozwala programiście wychwycić to nieprawidłowe przypisanie wskaźnika podczas kompilacji.

int *q = static_cast<int*>(&c); // compile-time error

Możesz także sprawdzić tę stronę, aby uzyskać więcej informacji na temat rzutowań w C ++: Kliknij tutaj

bryza
źródło
17
Myślę, że zamiast „4-bajtowego wskaźnika” miałeś na myśli „wskaźnik do 4-bajtowego typu danych”
iheanyi
ale pozwala int q = static_cast <int> (c);
TonyParker
3
@TonyParker To dlatego, że nie ma nic złego w tej linii.
Braden Best
15

Zobacz Porównanie operatorów rzutujących w C ++ .

Jednak użycie tej samej składni do różnych operacji rzutowania może spowodować, że intencje programisty są niejasne.

Ponadto znalezienie konkretnego typu obsady w dużej bazie kodu może być trudne.

ogólność obsady w stylu C może być przesadna w sytuacjach, w których wszystko, czego potrzeba, to prosta konwersja. Możliwość wyboru między kilkoma różnymi operatorami odlewania o różnym stopniu mocy może uniemożliwić programistom nieumyślne rzutowanie na niewłaściwy typ.

Eugene Yokota
źródło
14
struct A {};
struct B : A {};
struct C {}; 

int main()
{
    A* a = new A;    

    int i = 10;

    a = (A*) (&i); // NO ERROR! FAIL!

    //a = static_cast<A*>(&i); ERROR! SMART!

    A* b = new B;

    B* b2 = static_cast<B*>(b); // NO ERROR! SMART!

    C* c = (C*)(b); // NO ERROR! FAIL!

    //C* c = static_cast<C*>(b); ERROR! SMART!
}
Rishi Khaneja
źródło
5
Czy mógłby Pan uściślić swoją odpowiedź, dodając nieco więcej opisu oferowanego rozwiązania?
abarisone
1
Myślę, że odpowiedź pokazuje, że „static_casts” sprawdza konwersje typów, aby upewnić się, że są one wzdłuż prawidłowych ścieżek na wykresie hierarchii. W tym konkretnym przykładzie rzutowanie z A * na B * lub B * na A * jest dozwolone, ponieważ A i B tworzą ścieżkę na wykresie hierarchicznym. C * nie znajduje się na ścieżce, więc static_cast spowoduje błąd kompilacji. Sidenote: Warto zauważyć, że rzutowanie z A * na B * może spowodować NULL z dynamicznym rzutowaniem w czasie wykonywania, w zależności od prawdziwego obiektu bazowego.
Tommy Chen
7

Świetny post wyjaśniający różne obsady w C / C ++ i co naprawdę robi obsada w stylu C: https://anteru.net/blog/2007/12/18/200/index.html

Odlewanie w stylu C, przy użyciu składni zmiennej (typ). Najgorsze, jakie kiedykolwiek wymyślono. Próbuje to wykonać następujące rzutowania, w tej kolejności: (patrz także C ++ Standard, 5.4 expr.cast akapit 5)

  1. const_cast
  2. static_cast
  3. static_cast, po którym następuje const_cast
  4. reinterpret_cast
  5. reinterpret_cast obserwowane przez const_cast
Ying Xiong
źródło
5

static_castsprawdza w czasie kompilacji, czy konwersja nie jest między oczywiście niekompatybilnymi typami. W przeciwieństwie do tego dynamic_cast, sprawdzanie zgodności typów nie jest wykonywane w czasie wykonywania. Ponadto static_castkonwersja niekoniecznie jest bezpieczna.

static_cast służy do konwersji ze wskaźnika na klasę podstawową na wskaźnik na klasę pochodną lub między typami rodzimymi, takimi jak enum na int lub float na int.

Użytkownik static_castmusi upewnić się, że konwersja jest bezpieczna.

Rzutowanie w stylu C nie wykonuje żadnej kontroli ani podczas kompilacji, ani w czasie wykonywania.

Kiriloff
źródło
3

Ponieważ istnieje wiele różnych rodzajów rzutowania, z których każdy ma inną semantykę, static_cast <> pozwala powiedzieć „Robię legalną konwersję z jednego typu na inny”, np. Z int na double. Zwykła obsada w stylu C może oznaczać wiele rzeczy. Czy rzucasz w górę / w dół? Czy reinterpretujesz wskaźnik?

Doug T.
źródło