Мне всегда было любопытно по этому поводу - почему в C ++ мне приходится приводить возвращаемое значение из malloc
, а не в C?
Вот пример в C ++, который работает:
int *int_ptr = (int *)malloc(sizeof(int*));
И вот пример в C ++, который не работает (без приведения):
int *int_ptr = malloc(sizeof(int*));
Я слышал, что на самом деле в C приведение вывода из malloc ()
является ошибкой.
Кто-нибудь может прокомментировать эту тему?
Несколько моментов:
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, так что вероятность того, что вы столкнетесь с одной из этих старых реализаций, очень и очень мала.
Это потому, что C++ - сильно типизированный язык. В C++ неявные приведения разрешены только в том случае, если они являются "расширяющими", то есть если новый тип может содержать все значения, которые может содержать старый тип. Приведение от меньшего целочисленного типа к большему целочисленному типу разрешено; приведение от любого типа указателя к void*
разрешено; приведение от подкласса к его суперклассу разрешено. Все остальные приведения должны быть сделаны явно, тем самым говоря компилятору: "Я знаю, что делаю, это не ошибка".
malloc()
возвращает void*
, который может быть чем угодно, поэтому компилятор не может гарантировать, что ваше приведение будет успешным (или осмысленным). Используя явное приведение, вы сообщаете компилятору, что то, что вы делаете, действительно намеренно.
В языке C, напротив, нет таких жестких правил приведения; вы можете с радостью приводить любые два типа, и вы, как программист, несете ответственность за то, чтобы в результате не произошло ничего плохого.
C поддерживает неявное приведение из void *
к другим типам указателей. C ++ запрещает это.
Одна из причин, по которой в C не одобряется явное приведение возвращаемого значения malloc
, заключается в том, что если подпись malloc
не включена в текущий модуль компиляции, компилятор будет считать, что что тип возвращаемого значения - int
, и неявное преобразование его в тип указателя, который вы назначаете, приводит к предупреждению во время компиляции, которое вы должны немедленно устранить. При явном приведении, если вы сделаете эту ошибку, предупреждение не будет выдано.