Почему C ++ требует приведения для malloc (), а C нет?

Мне всегда было любопытно по этому поводу - почему в C ++ мне приходится приводить возвращаемое значение из malloc , а не в C?

Вот пример в C ++, который работает:

int *int_ptr = (int *)malloc(sizeof(int*));

И вот пример в C ++, который не работает (без приведения):

int *int_ptr = malloc(sizeof(int*));

Я слышал, что на самом деле в C приведение вывода из malloc () является ошибкой.

Кто-нибудь может прокомментировать эту тему?

39
задан Ciro Santilli 新疆改造中心法轮功六四事件 4 May 2016 в 16:57
поделиться

3 ответа

Несколько моментов:

C позволяет неявно преобразовывать указатели void в любые другие типы объектных указателей. C++ этого не делает.

Приведение результата malloc() в C подавит полезную диагностику, если вы забудете включить stdlib.h или иначе не будете иметь объявления для malloc() в области видимости. Помните, что если C увидит вызов функции без предварительного объявления, он будет считать, что функция возвращает int. Если у вас нет объявления для malloc() и вы оставите приведение, вы получите диагностику о том, что вы пытаетесь присвоить несовместимые типы (int указателю). Если вы приведете результат, вы подавите диагностику и потенциально будете иметь проблемы во время выполнения, поскольку не гарантировано, что преобразование значения указателя в int и обратно в указатель даст вам полезный результат.

Если вы пишете на C++, вам следует использовать new и delete вместо malloc() и free(). Да, да, да, я слышал все причины, по которым люди хотят, чтобы их код компилировался как на C и C++, но преимущества использования правильного инструмента управления памятью для языка перевешивают затраты на поддержку двух версий IMO.

Примечание: тип void * был добавлен в стандарт C89; более ранние версии C имели malloc(), возвращающие char *, поэтому в тех версиях приведение было необходимым, если вы присваивали результат другому типу указателя. Однако почти все поддерживают по крайней мере стандарт C89, так что вероятность того, что вы столкнетесь с одной из этих старых реализаций, очень и очень мала.

34
ответ дан 27 November 2019 в 02:45
поделиться

Это потому, что C++ - сильно типизированный язык. В C++ неявные приведения разрешены только в том случае, если они являются "расширяющими", то есть если новый тип может содержать все значения, которые может содержать старый тип. Приведение от меньшего целочисленного типа к большему целочисленному типу разрешено; приведение от любого типа указателя к void* разрешено; приведение от подкласса к его суперклассу разрешено. Все остальные приведения должны быть сделаны явно, тем самым говоря компилятору: "Я знаю, что делаю, это не ошибка".

malloc() возвращает void*, который может быть чем угодно, поэтому компилятор не может гарантировать, что ваше приведение будет успешным (или осмысленным). Используя явное приведение, вы сообщаете компилятору, что то, что вы делаете, действительно намеренно.

В языке C, напротив, нет таких жестких правил приведения; вы можете с радостью приводить любые два типа, и вы, как программист, несете ответственность за то, чтобы в результате не произошло ничего плохого.

13
ответ дан 27 November 2019 в 02:45
поделиться

C поддерживает неявное приведение из void * к другим типам указателей. C ++ запрещает это.

Одна из причин, по которой в C не одобряется явное приведение возвращаемого значения malloc , заключается в том, что если подпись malloc не включена в текущий модуль компиляции, компилятор будет считать, что что тип возвращаемого значения - int , и неявное преобразование его в тип указателя, который вы назначаете, приводит к предупреждению во время компиляции, которое вы должны немедленно устранить. При явном приведении, если вы сделаете эту ошибку, предупреждение не будет выдано.

9
ответ дан 27 November 2019 в 02:45
поделиться