Czy rzucę wynik malloca?

W to pytanie , ktoś zasugerował w komentarz, że powinienem nie rzut wyniku malloc, czyli

int *sieve = malloc(sizeof(int) * length);

Zamiast:

int *sieve = (int *) malloc(sizeof(int) * length);
Dlaczego miałoby tak być?
Author: Engineero, 2009-03-03

26 answers

Nie ; ty nie rzucaj wyniku, ponieważ:

  • jest to niepotrzebne, ponieważ {[2] } jest automatycznie i bezpiecznie promowany do dowolnego innego typu wskaźnika w tym przypadku.
  • dodaje bałagan do kodu, rzuty nie są zbyt łatwe do odczytania(zwłaszcza jeśli typ wskaźnika jest długi).
  • To sprawia, że się powtarzasz, co jest generalnie złe.
  • może ukryć błąd, jeśli zapomniałeś dołączyć <stdlib.h>. Może to spowodować awarie (lub, co gorsza, , a nie spowodować awaria do czasu, aż w jakiejś zupełnie innej części kodu). Zastanów się, co się stanie, jeśli wskaźniki i liczby całkowite są różnej wielkości; następnie ukrywasz Ostrzeżenie przez odlewanie i możesz stracić bity zwracanego adresu. Uwaga: od C11 funkcje niejawne znikają z C, a ten punkt nie ma już znaczenia, ponieważ nie ma automatycznego założenia, że funkcje nierejestrowane zwracają int.

Jako wyjaśnienie zauważ, że powiedziałem "nie rzucasz", a nie " nie potrzebujesz do obsady". Moim zdaniem brak obsady, nawet jeśli dobrze to zrozumiałeś. Nie ma po prostu żadnych korzyści z robienia tego, ale kilka potencjalnych zagrożeń, a w tym Obsada wskazuje, że nie wiesz o ryzyku.

Zauważ również, jak podkreślają komentatorzy, że powyższe mówi o prostym C, a nie c++. Bardzo mocno wierzę w C i c++ jako osobne języki.

Aby dodać więcej, Twój kod niepotrzebnie powtarza informacje o typie (int), które mogą powodować błędy. Lepiej jest dereferować wskaźnik używany do przechowywania zwracanej wartości, aby "zablokować" te dwa razem:

int *sieve = malloc(length * sizeof *sieve);

To również przesuwa length do przodu, aby zwiększyć widoczność i upuszcza zbędne nawiasy z sizeof; są potrzebne tylko , gdy argument jest nazwą typu. Wiele osób zdaje się nie wiedzieć (lub ignorować) tego, co sprawia, że ich kod jest bardziej gadatliwy. Pamiętaj: sizeof nie jest funkcją! :)


Podczas przesuwania length do przodu Może zwiększenie widoczności w niektórych rzadkich przypadkach należy również zwrócić uwagę, że w ogólnym przypadku lepiej jest zapisać wyrażenie jako: {]}

int *sieve = malloc(sizeof *sieve * length);

Ponieważ zachowanie sizeof najpierw, w tym przypadku, zapewnia mnożenie za pomocą co najmniej size_t matematyki.

Porównaj: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) drugi może przepełnić length * width, gdy width i length są mniejszymi typami niż size_t.

 1958
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-01 05:52:36

W C, nie musisz rzucać wartości zwracanej malloc. Wskaźnik do void zwracany przez malloc jest automatycznie konwertowany na właściwy typ. Jeśli jednak chcesz, aby Twój kod był kompilowany za pomocą kompilatora C++, potrzebny jest cast. Preferowaną alternatywą wśród społeczności jest stosowanie następujących rozwiązań:

int *sieve = malloc(sizeof *sieve * length);

Co dodatkowo uwalnia cię od konieczności martwienia się o zmianę prawej strony wyrażenia, jeśli kiedykolwiek zmienisz typ sieve.

Rzuty są złe, jak ludzie mają / align = "left" / Specjalnie odlewy pointerowe.

 332
Author: dirkgently,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 15:15:48

You do cast, because:

  • sprawia, że Twój kod jest bardziej przenośny pomiędzy C i C++, a jak pokazuje doświadczenie, wielu programistów twierdzi, że pisze W C, Kiedy naprawdę pisze W C++ (lub C plus lokalne rozszerzenia kompilatora).
  • Niezastosowanie się do tego może ukryć błąd: zwróć uwagę na wszystkie przykłady mylące, kiedy pisać type * versus type **.
  • pomysł, że dzięki niemu nie zauważysz, że nie udało Ci się #include odpowiedniego nagłówka plik the forest for the trees . Jest to to samo co powiedzenie " nie martw się o to, że nie poprosiłeś kompilatora, aby narzekał, że nie widzisz prototypów - tego nieznośnego stdlib.h jest naprawdę ważną rzeczą do zapamiętania!"
  • wymusza dodatkowe poznawcze sprawdzenie krzyżowe . Umieszcza (domniemany) pożądany typ tuż obok arytmetyki, którą robisz dla surowego rozmiaru tej zmiennej. Założę się, że można zrobić tak badania, które pokazują, że malloc() błędy są łapane znacznie szybciej, gdy jest gips. Podobnie jak w przypadku twierdzeń, adnotacje ujawniające intencję zmniejszają błędy.
  • powtarzanie się w sposób, który maszyna może sprawdzić, jest często świetnym pomysłem. W rzeczywistości tym jest twierdzenie, a użycie cast jest twierdzeniem. Twierdzenia są nadal najbardziej ogólną techniką, jaką mamy do poprawienia kodu, ponieważ Turing wpadł na ten pomysł wiele lat temu.
 302
Author: Ron Burk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-02 14:54:07

Jak inni stwierdzili, nie jest on potrzebny dla C, ale dla C++. Jeśli myślisz, że zamierzasz skompilować swój kod C za pomocą kompilatora C++, z tego powodu możesz użyć zamiast tego makra, takiego jak:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

W ten sposób można jeszcze napisać to w bardzo zwarty sposób:

int *sieve = NEW(int, 1);

I skompiluje się dla C i C++.

 153
Author: quinmars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-03 11:17:46

Z Wikipedii

Zalety odlewania

  • W tym cast może pozwolić program lub funkcja C skompilować jako c++.

  • Obsada pozwala na wersje sprzed 1989 roku malloc, które pierwotnie zwracały znak*.

  • Odlewanie może pomóc programiście zidentyfikować niespójności w doborze rozmiaru tekstu w przypadku zmiany typu wskaźnika docelowego, szczególnie jeśli wskaźnik jest zadeklarowany z dala od malloc() call (chociaż nowoczesne kompilatory i analizatory statyczne mogą ostrzegać o takim zachowaniu bez konieczności stosowania cast).

Wady odlewania

  • Zgodnie ze standardem ANSI C obsada jest zbędna.

  • Dodanie obsady może maskować brak dołączenia nagłówka stdlib.h , W której znajduje się prototyp malloca. W przypadku braku prototyp dla malloc, standard wymaga, aby kompilator C zakład malloc zwraca int. Jeśli nie ma obsady, ostrzeżenie jest wydane, gdy ta liczba całkowita jest przypisana do wskaźnika; jednak z Obsada, to Ostrzeżenie nie jest produkowane, ukrywając błąd. Na pewnym architektur i modeli danych (np. LP64 w systemach 64-bitowych, gdzie long i wskaźniki są 64-bitowe, a int 32-bitowe), ten błąd może faktycznie skutkuje nieokreślonym zachowaniem, jak deklarowane w sposób niejawny malloc zwraca 32-bitową wartość, podczas gdy faktycznie zdefiniowana funkcja Zwraca wartość 64-bitową. W zależności o wywoływaniu konwencji i pamięci układ, może to spowodować rozbijanie stosu. Ten problem jest mniej prawdopodobny niezauważalne we współczesnych kompilatorach, gdyż jednolicie produkują ostrzeżenia, że została użyta niezgłoszona funkcja, więc Ostrzeżenie będzie / align = "left" / Na przykład domyślnym zachowaniem GCC jest pokazanie ostrzeżenie o treści " niezgodna domyślna deklaracja wbudowanego funkcja " niezależnie od tego, czy obsada jest obecna, czy nie.

  • Jeśli typ wskaźnika jest zmieniony w deklaracji, można ponadto, trzeba zmienić wszystkie linie, gdzie malloc jest wywołany i Obsada.

Chociaż malloc bez odlewania jest preferowaną metodą i większość doświadczonych programistów wybiera ją , powinieneś użyć dowolnego, który chcesz mieć świadomość problemów.

Tzn: jeśli chcesz skompilować program C jako C++(chociaż są to osobne języki) powinieneś użyć malloc z castingiem.

 105
Author: ashiquzzaman33,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-26 12:04:52

W C można bezwarunkowo przekonwertować wskaźnik void na dowolny inny rodzaj wskaźnika, więc cast nie jest konieczny. Używanie jednego może sugerować przypadkowemu obserwatorowi, że istnieje jakiś powód, dla którego jest on potrzebny, co może być mylące.

 96
Author: PaulJWilliams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-13 00:35:43

Nie rzucasz wyniku malloca, ponieważ robiąc to dodaje bezsensowny bałagan do Twojego kodu.

Najczęstszym powodem, dla którego ludzie rzucają wynik malloca, jest to, że nie są pewni, jak działa język C. To znak ostrzegawczy: jeśli nie wiesz, jak działa dany mechanizm językowy, to nie zgaduj. Sprawdź to lub zapytaj o przepełnienie stosu.

Niektóre komentarze:

  • Wskaźnik void może być konwertowany do / z dowolnego innego typu wskaźnika bez wyraźnej obsady (C11 6.3.2.3 i 6.5.16.1).

  • C++ nie pozwala jednak na niejawny rzut pomiędzy void* a innym typem wskaźnika. Więc w C++ Obsada byłaby poprawna. Ale jeśli programujesz w C++, powinieneś użyć new, a nie malloc (). I nigdy nie powinieneś kompilować kodu C używając kompilatora C++.

    Jeśli chcesz obsługiwać zarówno C jak i c++ za pomocą tego samego kodu źródłowego, użyj przełączników kompilatora, aby zaznaczyć różnice. Nie próbujcie usatysfakcjonować obu standardów językowych z tym samym kodem, ponieważ nie są one kompatybilne.

  • Jeśli kompilator C nie może znaleźć funkcji, ponieważ zapomniałeś dołączyć nagłówek, pojawi się błąd kompilatora / linkera. Więc jeśli zapomnisz dołączyć <stdlib.h> to nic wielkiego, nie będziesz w stanie zbudować swojego programu.

  • Na kompilatorach ancient, które stosują wersję standardu, która ma ponad 25 lat, zapomnienie o dołączeniu <stdlib.h> spowodowałoby niebezpieczne zachowanie. Bo w tym ancient standard, funkcje bez widocznego prototypu domyślnie zamieniły Typ powrotu na int. Rzucenie wyniku z malloc jawnie ukryłoby ten błąd.

    Ale to naprawdę nie jest problem. Nie używasz 25-letniego komputera, więc dlaczego miałbyś używać 25-letniego kompilatora?

 87
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 08:53:05

W C otrzymujemy konwersję implicit z void* na dowolny inny wskaźnik (data).

 85
Author: EFraim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-13 00:35:15

Rzucanie wartości zwracanej przez malloc() nie jest teraz konieczne, ale chciałbym dodać jeden punkt, który wydaje się, że nikt nie wskazał:

W czasach starożytnych, to znaczy przed ANSI C dostarcza {[1] } jako typ ogólny wskaźników, char * jest typem dla takiego użycia. W takim przypadku cast może wyłączyć ostrzeżenia kompilatora.

Reference: C FAQ

 65
Author: Yu Hao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-14 02:28:44

Nie jest obowiązkowe wyświetlanie wyników malloc, ponieważ zwraca void*, A void* może być wskazywany na dowolny typ danych.

 48
Author: user968000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-03 06:10:35

Po prostu dodając moje doświadczenie, studiując inżynierię komputerową widzę, że dwóch lub trzech profesorów, których widziałem pisząc w C, zawsze rzucało malloca, jednak ten, o który prosiłem (z ogromnym CV i zrozumieniem C) powiedział mi, że jest to absolutnie niepotrzebne, ale tylko kiedyś było absolutnie konkretne, i aby dostać studentów do mentalności bycia absolutnie konkretnym. Zasadniczo casting nie zmieni niczego w tym, jak działa, robi dokładnie to, co mówi, przydziela pamięć i casting nie działa na to, dostajesz tę samą pamięć i nawet jeśli przez pomyłkę wrzucisz ją do czegoś innego (i jakoś unikniesz błędów kompilatora) C uzyska do niej dostęp w ten sam sposób.

Edit: Casting ma pewien punkt. Podczas korzystania z notacji tablicy, generowany kod musi wiedzieć, ile miejsc pamięci musi przejść, aby dotrzeć do początku następnego elementu, osiąga się to poprzez odlewanie. W ten sposób wiesz, że dla podwójnego idziesz 8 bajtów do przodu, podczas gdy dla int idziesz 4, i tak dalej. W ten sposób nie ma to wpływu, jeśli używasz notacji wskaźnikowej, w notacji tablicy staje się to konieczne.

 47
Author: user3079666,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 23:37:49

Wskaźnik void jest ogólnym wskaźnikiem, A C obsługuje niejawną konwersję z typu void pointer na inne typy, więc nie ma potrzeby jawnego typowania go.

Jeśli jednak chcesz, aby ten sam kod działał idealnie kompatybilnie na platformie C++, która nie obsługuje konwersji implicit, musisz wykonać typecasting, więc wszystko zależy od użyteczności.

 28
Author: Endeavour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-19 16:24:22

Zwracanym typem jest void*, który może być oddany do żądanego typu wskaźnika danych, aby mógł być dereferenceable.

 27
Author: swaps,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-18 21:33:00

Oto co Podręcznik GNU C Library Reference mówi:

Możesz zapisać wynik malloc do dowolnej zmiennej wskaźnika bez cast, ponieważ ISO C automatycznie konwertuje typ void * na inny rodzaj wskaźnika w razie potrzeby. Ale obsada jest konieczna w kontekstach inne niż operatory przypisania lub jeśli chcesz, aby Twój kod działał w tradycyjnym C.

I rzeczywiście norma ISO C11 (p347) mówi tak:

The wskaźnik zwrócony, jeśli alokacja się powiedzie jest odpowiednio wyrównany tak że może być przypisany do wskaźnika do dowolnego typu obiektu z podstawowym wymogiem dostosowania, a następnie wykorzystywane do uzyskania dostępu do takiego obiektu lub tablicy takich obiektów w przydzielonej przestrzeni (aż do spacja jest wyraźnie dealokowana)

 27
Author: Slothworks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-05 19:48:51

To zależy od języka programowania i kompilatora. Jeśli używasz malloc W C nie ma potrzeby wpisywania cast it, ponieważ automatycznie wpisuje cast, jednak jeśli używasz C++, powinieneś wpisać cast, ponieważ malloc zwróci typ void*.

 24
Author: Jeyamaran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-04 14:29:20

W języku C wskaźnik void może być przypisany do dowolnego wskaźnika, dlatego nie należy używać typu cast. Jeśli chcesz" wpisać Bezpieczny " przydział, mogę polecić następujące funkcje makr, które zawsze używam w moich projektach C:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

Z tymi na miejscu można po prostu powiedzieć

NEW_ARRAY(sieve, length);

Dla tablic nie dynamicznych, trzecim niezbędnym makrem funkcji jest

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

Co czyni pętle tablic bezpieczniejszymi i wygodniejszymi:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}
 24
Author: August Karlstrom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-08 08:36:51

Ludzie kiedyś GCC i Clang są zepsute. Nie jest tak dobrze.

Byłem dość przerażony przez lata przez oszałamiająco stare Kompilatory, których musiałem używać. Często firmy i menedżerowie przyjmują ultra-konserwatywne podejście do zmian kompilatorów i nie będą nawet testować , czy nowy kompilator (z lepszą zgodnością ze standardami i optymalizacją kodu) będzie działał w ich systemie. Praktyczną rzeczywistością dla pracujących programistów jest to, że gdy kodowanie musisz zakryć swoje podstawy i, niestety, tworzenie mallocsów jest dobrym nawykiem, jeśli nie możesz kontrolować, jaki kompilator może być zastosowany do Twojego kodu.

Sugerowałbym również, że wiele organizacji stosuje własny standard kodowania i że to powinna być metoda, którą ludzie stosują, jeśli jest zdefiniowana. W przypadku braku wyraźnych wskazówek zazwyczaj wybieram się na kompilację raczej wszędzie, niż niewolnicze przestrzeganie standardu.

Argument, że nie jest konieczne w obecnych standardach jest dość ważne. Ale ten argument pomija praktyczne aspekty realnego świata. Nie kodujemy w świecie rządzonym wyłącznie standardem dnia, ale praktycznymi aspektami tego, co lubię nazywać "polem rzeczywistości lokalnego zarządzania". I to jest wygięte i skręcone bardziej niż czasoprzestrzeń kiedykolwiek była. :-)

YMMV.

Myślę, że casting malloca to operacja defensywna. Nie Ładna, nie idealna, ale ogólnie bezpieczna. (Szczerze mówiąc, jeśli nie w zestawie stdlib.h więc masz sposób więcej problemów niż casting malloc ! ).

 14
Author: StephenG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-04 17:27:54

Dodałem cast po prostu, aby pokazać dezaprobatę brzydkiej dziury w systemie typów, która pozwala kodowi, takim jak Poniższy fragment, kompilować bez diagnostyki, mimo że żadne Cast nie są używane do doprowadzenia do złej konwersji: {]}

double d;
void *p = &d;
int *q = p;

Szkoda, że nie istnieje (a nie ma w C++) i tak rzucam. Reprezentuje mój gust i moją politykę programową. Nie tylko rzucam wskaźnik, ale skutecznie, rzucam głosowanie i [22]} wyrzucam demony głupoty [23]}. If I can ' t właściwie wyrzuć głupotę , to przynajmniej pozwól mi wyrazić chęć zrobienia tego gestem protestu.

W rzeczywistości dobrą praktyką jest owijanie malloc (i znajomych) funkcjami zwracającymi unsigned char * i w zasadzie nigdy nie używanie void * w kodzie. Jeśli potrzebujesz ogólnego wskaźnika-do-dowolnego-obiektu, użyj char * lub unsigned char * i miej rzuty w obu kierunkach. Jedynym relaksem, który można sobie odprężyć, być może, jest korzystanie z funkcji takich jak memset i memcpy bez odlewy.

Na temat castingu i kompatybilności z C++, jeśli piszesz swój kod tak, aby kompilował się zarówno w C jak i C++ (w takim przypadku musisz oddać wartość zwracaną malloc przy przypisywaniu go do czegoś innego niż void *), możesz zrobić bardzo pomocną rzecz dla siebie: możesz użyć makr do castingu, które tłumaczą się na C++ podczas kompilacji jako C++, ale redukują do C castingu 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, to proste grep przeszukanie bazy kodów dla tych identyfikatorów pokaże ci, gdzie znajdują się wszystkie odlewy, dzięki czemu możesz sprawdzić, czy któryś z nich jest nieprawidłowy.

Następnie, jeśli regularnie kompilujesz kod z C++, wymusi to użycie odpowiedniego cast. Na przykład, jeśli użyjesz strip_qual Tylko do usunięcia const lub volatile, ale program zmieni się w taki sposób, że konwersja tekstu jest teraz zaangażowana, otrzymasz diagnostykę i będziesz musiał użyć kombinacji odlewów, aby uzyskać pożądana konwersja.

Aby pomóc ci stosować się do tych makr, GNU C++ (nie C!) kompilator ma piękną funkcję: opcjonalną diagnostykę, która jest produkowana dla wszystkich wystąpień w stylu C odlewów.

     -Wold-style-cast (C++ and Objective-C++ only)
         Warn if an old-style (C-style) cast to a non-void type is used
         within a C++ program.  The new-style casts (dynamic_cast,
         static_cast, reinterpret_cast, and const_cast) are less vulnerable
         to unintended effects and much easier to search for.

Jeśli twój kod C kompiluje się jako c++, możesz użyć tej opcji -Wold-style-cast, aby dowiedzieć się wszystkich wystąpień składni odlewania (type), które mogą wkradać się do kodu, i kontynuować tę diagnostykę, zastępując ją odpowiednim wyborem spośród powyższych makr (lub innym sposobem). jednoczesne stosowanie, jeśli jest to konieczne).

To traktowanie konwersji jest największym pojedynczym samodzielnym technicznym uzasadnieniem pracy w" czystym C": połączonym dialekcie C i c++, co z kolei technicznie uzasadnia odlewanie wartości zwracanej malloc.

 12
Author: Kaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-30 00:23:45

Casting jest tylko dla C++ nie C.In jeśli używasz kompilatora C++, lepiej zmień go na kompilator C.

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 15:58:49

Najlepszą rzeczą do zrobienia podczas programowania w C, gdy jest to możliwe:

  1. Skompiluj swój program za pomocą kompilatora C z włączonymi ostrzeżeniami -Wall i napraw wszystkie błędy i ostrzeżenia
  2. upewnij się, że nie ma żadnych zmiennych zadeklarowanych jako auto
  3. następnie skompilować go za pomocą kompilatora C++ z -Wall i -std=c++11. Napraw wszystkie błędy i ostrzeżenia.
  4. teraz skompiluj ponownie używając kompilatora C. Twój program powinien teraz kompilować się bez żadnego ostrzeżenia i zawierać mniej robaki.

Ta procedura pozwala skorzystać z C++ strict type checking, zmniejszając w ten sposób liczbę błędów. W szczególności ta procedura zmusza cię do włączenia stdlib.h lub otrzymasz

malloc nie został zgłoszony w tym zakresie

A także zmusza cię do oddania wyniku malloc albo dostaniesz

Nieprawidłowa konwersja z void* na T*

Albo jaki jest Twój typ celu.

Jedyne korzyści z pisząc w C zamiast c++ mogę znaleźć

  1. C ma dobrze określone ABI
  2. C++ może generować więcej kodu [exceptions, RTTI, templates, runtime polimorfizm]

Zwróć uwagę, że drugie wady powinny w idealnym przypadku zniknąć przy użyciu podzbioru wspólnego dla C razem zstatyczną cechą polimorficzną.

Dla tych, którzy uznają ścisłe reguły C++ za niewygodne, możemy użyć funkcji C++11 z typem inferred

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
 10
Author: user877329,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-24 15:44:39

Nie, Nie rzucasz wyniku malloc().

Ogólnie rzecz biorąc, ty nie rzucaj do lub z void *.

Typowym powodem, dla którego tego nie robi, jest to, że niepowodzenie może pozostać niezauważone. To już nie jest problem przez długi czas, ponieważ C99 uczynił deklaracje funkcji niejawnych nielegalnymi, więc jeśli twój kompilator będzie zgodny z co najmniej C99, otrzymasz komunikat diagnostyczny.

Ale jest o wiele silniejszy powód aby nie wprowadzać niepotrzebnych pointer rzuca:

W C, rzut wskaźnika jest prawie zawsze błędem . Jest to spowodowane następującą regułą (§6.5 p7 w N1570, najnowszym projekcie C11):

Obiekt powinien mieć zapisaną wartość dostępną tylko przez wyrażenie lvalue, które ma jeden z następujące rodzaje:
- Typ zgodny z typem efektywnym obiektu,
- kwalifikowana wersja typu kompatybilna z efektywnym typem obiektu,
- Typ jest to typ podpisany lub niepodpisany odpowiadający typowi efektywnemu obiekt,
- typ, który jest typem podpisanym lub niepodpisanym odpowiadającym kwalifikowanej wersji efektywny typ obiektu,
- typu agregatowego lub unijnego, który obejmuje jeden z wyżej wymienionych typów wśród swoich członkowie (w tym, rekurencyjnie, członek podagregatu lub zawartego związku), lub
- typ postaci.

Jest to również znane jako ścisłe aliasing reguła . Zatem poniższy kod to undefined behavior :

long x = 5;
double *p = (double *)&x;
double y = *p;

I, czasami zaskakująco, jest również:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

Czasami, czy trzeba rzucać wskaźniki, ale biorąc pod uwagę ścisłą zasadę aliasingu , trzeba być bardzo ostrożnym z tym. Tak więc, każde wystąpienie wskaźnika rzuconego w Twoim kodzie jest miejscem, w którym musisz dokładnie sprawdzić jego ważność . Dlatego nigdy nie piszesz niepotrzebnego wskaźnika Obsada

Tl;dr

W skrócie: ponieważ w C jakiekolwiek wystąpienie pointer cast powinno wywołać czerwoną flagę dla kodu wymagającego szczególnej uwagi, nigdy nie należy pisać niepotrzebnych pointer Cast.


Uwagi boczne:

  • Są przypadki, w których rzeczywiście potrzebujesz obsady dovoid *, np. jeśli chcesz wydrukować wskaźnik:

    int x = 5;
    printf("%p\n", (void *)&x);
    

    Rzut jest tu konieczny, ponieważ printf() jest funkcją zmienną, więc Ukryte konwersje nie działają.

  • W C++ sytuacja jest inna. Rzutowanie typów wskaźników jest dość powszechne (i poprawne), gdy mamy do czynienia z obiektami klas pochodnych. Dlatego w C++ konwersja do i z void * jest , a nie niejawna. C++ ma cały zestaw różnych smaków odlewania.

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-08 08:54:22

Wolę obsadę, ale nie ręcznie. Moim ulubionym jest używanie makr g_new i g_new0 z biblioteki glib. Jeśli glib nie jest używany, dodałbym podobne makra. Te makra zmniejszają powielanie kodu bez uszczerbku dla bezpieczeństwa typów. Jeśli źle ustawisz typ, otrzymasz Ukryty rzut między wskaźnikami nie-void, co spowoduje ostrzeżenie (błąd w C++). Jeśli zapomnisz dołączyć nagłówek definiujący g_new i g_new0, pojawi się błąd. g_new i g_new0 obie przyjmują te same argumenty, w przeciwieństwie malloc to wymaga mniej argumentów niż calloc. Po prostu dodaj 0, aby uzyskać zero-inicjalizowaną pamięć. Kod można skompilować za pomocą kompilatora C++ bez zmian.

 10
Author: proski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-26 18:16:38

Koncepcja void pointer polega na tym, że może być przypisany do dowolnego typu danych, dlatego malloc zwraca void. Również musisz być świadomy automatycznego typecasting. Więc nie jest obowiązkowe rzucanie wskaźnika, chociaż musisz to zrobić. Pomaga w utrzymaniu czystości kodu i pomaga debugować

 9
Author: iec2011007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-29 05:53:42

Wskaźnik void jest ogólnym wskaźnikiem, A C obsługuje niejawną konwersję z typu void pointer na inne typy, więc nie ma potrzeby jawnego typowania go.

Jeśli jednak chcesz, aby ten sam kod działał idealnie kompatybilnie na platformie C++, która nie obsługuje konwersji implicit, musisz wykonać typecasting, więc wszystko zależy od użyteczności.

 5
Author: dhana govindarajan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-18 10:36:57
  1. Jak inni stwierdzili, nie jest on potrzebny dla C, ale dla C++.

  2. W tym cast może pozwolić program lub funkcja C skompilować jako c++.

  3. W C jest to niepotrzebne, ponieważ void * jest automatycznie i bezpiecznie promowany do dowolnego innego typu wskaźnika.

  4. Ale jeśli rzucisz wtedy, może ukryć błąd, jeśli zapomnisz dołączyć stdlib.h . Może to spowodować awarie (lub, co gorsza, nie spowodować awarii aż w jakiś zupełnie inny sposób kod).

    Ponieważ stdlib.h zawiera prototyp malloca. W brak prototypu dla malloc, standard wymaga, aby C kompilator zakłada, że malloc zwraca int. Jeśli nie ma obsady, a ostrzeżenie jest wydawane, gdy ta liczba całkowita jest przypisana do wskaźnika; jednak w przypadku obsady ostrzeżenie to nie jest produkowane, ukrywając błąd.

 5
Author: Mohit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-08 10:09:54

Odlewanie malloca jest niepotrzebne w C, ale obowiązkowe w C++.

Casting jest zbędny w C ze względu na:

  • void * jest automatycznie i bezpiecznie promowany do dowolnego innego typu wskaźnika w przypadku C.
  • może ukryć błąd, jeśli zapomniałeś dołączyć <stdlib.h>. Może to spowodować awarie.
  • jeśli wskaźniki i liczby całkowite są różnej wielkości, to ukrywasz Ostrzeżenie przez rzucanie i możesz stracić bity zwracanego adresu.
  • Jeśli typ jeśli wskaźnik jest zmieniany w deklaracji, może być również konieczna zmiana wszystkich linii, w których malloc jest wywoływana i rzucana.

Z drugiej strony, casting może zwiększyć przenośność Twojego programu. umożliwia kompilację programu lub funkcji C jako c++.

 2
Author: Aashish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-09 14:00:42