Зачем приводить возвращаемое значение free к void?


82

Я читаю книгу ( Программирование с помощью POSIX Threads by Butenhof, 1997), в которой используется C, и наткнулся на следующую строку:

(void)free(data);

Здесь dataпросто указатель на выделенную структуру,

data = malloc(sizeof(my_struct_t));

Почему результат freeбудет приведен к void?

Из моего понимания C это, кажется, не имеет смысла по двум причинам:

  • Бесплатная функция уже возвращает void
  • Код не использует возвращаемое значение (он даже не присваивается переменной)

Книга была написана в 1997 году. Это что-то вроде наследства?

Автор упоминает, что примеры были запущены на Digital Unix 4.0d, но я до сих пор не могу представить себе причину когда-либо приводить результат функции, если вы не собираетесь использовать этот результат.


Некоторые возможные объяснения можно найти здесь: stackoverflow.com/questions/689677/…
Тимбо

3
Из любопытства, какова дата публикации вашей книги на С? (Какая это книга?) Если она выйдет примерно в 1995 году, то для этого может быть какое-то оправдание - стандартные компиляторы Си раньше не были повсеместными. Если он опубликован после этого и все еще содержит актерский состав (и не объясняет почему), подумайте о том, какие другие вредные привычки он преподает вам. Получите более свежую книгу!
Джонатан Леффлер


3
@JonathanLeffler, как упоминалось в моем первоначальном посте, книга была опубликована в 1997 году и использовала UNIX 4.0d. Книга "Программирование с использованием потоков POSIX" Дэвида Р. Бутенхофа. До сих пор оно было очень информативным и написано одним из первоначальных авторов стандарта потоков POSIX.
Адам Джонстон

6
Я использовал свою копию на прошлой неделе - да, это все еще полезно. Это было написано на пороге «вездесущего стандарта C» (я сказал «около 1995»). «UNIX 4.0d» звучит как Digital UNIX - именно здесь работал Butenhof, и в предисловии об этом упоминается. Относитесь к актерскому составу free()как к странности в книге, которую вам не нужно подражать. Когда-то давно это было уместно, но уже не актуально.
Джонатан Леффлер

Ответы:


100

Если мы говорим о стандартной freeфункции, то ее прототип

void free(void *ptr);

Поэтому актерский состав совершенно бесполезен.
Теперь немного спекуляций.

Автор, возможно, забыл включить stdlib.hзаголовок, объявляющий этот прототип, поэтому компилятор принимает тип возвращаемого значения как int. Теперь во время статического анализа этого кода компилятор предупреждал о неиспользованном возвращаемом значении того, что он считает неработающим void. Такие предупреждения обычно замалчиваются путем добавления актеров к void.


50
Но обратите внимание, что если приведение было введено по предположительной причине, то использование его для отключения предупреждения является неправильным . В этом случае компилятор будет приписывать тип, отличный от freeтого, который он имеет на самом деле, в результате чего вызов имеет неопределенное поведение (предположим, семантика C90, когда вызов необъявленной функции по своей природе не показывает UB во всех случаях). На практике вполне вероятно, что это приведет к добросовестному поведению в некоторых системах. Правильное решение - предоставить правильное объявление для функции.
Джон Боллинджер

11
Примечательно, что примеры в разделе «Программирование с потоками POSIX» часто не включают соответствующие стандартные заголовки. Возможно, это была плохая практика автора, они могли использовать нестандартную настройку компилятора, которая по умолчанию включала все стандартные библиотеки.
Лундин

74

Это было бы наследством!

До того, как появился стандарт C, free()функция была бы (неявно) типа int- потому что еще не было надежного типа voidдля возврата. Не было возвращено значение.

Когда код был впервые изменен для работы со стандартными компиляторами Си, он, вероятно, не включал <stdlib.h>(потому что он не существовал до стандарта). Старый код писал extern char *malloc();(может быть без extern) для функций распределения (аналогично для calloc()и realloc()), и не нужно было объявлять free(). И код затем приведёт возвращаемое значение к правильному типу - потому что это было необходимо по крайней мере в некоторых системах (включая ту, на которой я изучал C).

Некоторое время спустя (void)было добавлено приведение, чтобы сообщить компилятору (или, что более вероятно, lint), что «возвращаемое значение из free()намеренно игнорируется», чтобы избежать жалоб. Но было бы лучше добавить <stdlib.h>и позволить его объявлению extern void free(void *vp);сообщить lintкомпилятору, что игнорировать не стоит.

JFTR: Еще в середине 80-х годов ICL Perq изначально был ориентирован на слово, и char *адрес для ячейки памяти отличался от «указателя что-нибудь» в том же месте. Важно было char *malloc()как-то объявить ; было важно преобразовать результат из него в любой другой тип указателя. Приведение фактически изменило число, используемое процессором. (Было также много радости, когда основная память в наших системах была обновлена ​​с 1 МБ до 2 МБ - поскольку ядро ​​использовало около 3/4 МБ, это означало, что пользовательские программы могли использовать 1 1/4 МБ до подкачки и т. Д.)


9
Я только что открыл копию K & R, 1-е издание, которое содержит реализацию free()на с. 177, который неявно возвращается int.
ex nihilo

9
Конечно - voidбыл добавлен в некоторые системы (возможно, Unix System III) до выпуска стандарта, но это не было частью C, когда K & R 1st Edn был написан (1978). Функция, которая не возвращала значение, была объявлена ​​без возвращаемого типа (что означало, что она возвращалась int), и до тех пор, пока вы не использовали значение, которое не было возвращено, проблем не было. Стандарт C90 должен был относиться к такому коду как к допустимому - он потерпел бы неудачу, как если бы он не был стандартным. Но C99 удалил intправила «неявного » и «неявного объявления функции». Не весь код в мире догнал.
Джонатан Леффлер

5
Op утверждает, что книга была написана в 1997 году. То, о чем вы говорите здесь, является очень ранним предварительным стандартом «K & R C», и кажется маловероятным, что кто-либо вообще напишет книгу об этом. Насколько мне известно, единственной такой книгой действительно было первое издание K & R.
Лундин

Это была частая (если не смешная) практика - не включать заголовки, если вы думали, что можете избежать неявного объявления, потому что люди думали, что это сократит время сборки.
Спенсер

Кто-нибудь использует (void)бросок для printf()??
Луис Колорадо

11

Этот актерский состав не нужен. Это, вероятно, не было бы в то время, когда C был стандартизирован в форме C89.

Если бы это было так, это было бы связано с неявным объявлением . Обычно это означало, что человек, пишущий код, забыл #include <stdlib.h>и использовался статический анализатор. Это не лучший обходной путь, и гораздо лучшая идея была бы #include <stdlib.h>вместо этого. Вот некоторая формулировка из C89 о неявном объявлении:

Если выражение, которое предшествует списку аргументов в скобках в вызове функции, состоит исключительно из идентификатора, и если для этого идентификатора не видно никакого объявления, идентификатор неявно объявляется точно так, как если бы в самом внутреннем блоке, содержащем вызов функции, объявление

extern int identifier();

появился.

Но это странно, потому что они не приводят mallocни к какому результату , mallocи freeнаходятся в одном заголовочном файле.

Также возможно, что это просто ошибка или какой-то способ сообщить читателю, что freeрезультат не возвращается.


5
Тот факт, что язык становится стандартизированным, не означает, что каждый немедленно обновляет свой инструментарий и код, чтобы соответствовать ему. Для старого K "R & R" C вполне вероятно, что он застрял еще около 8 лет. Тем не менее, я согласен, что странно, что инструмент статического анализа потребовал бы приведение для, freeно не для malloc.
dan04

4
@ dan04 Вы обычно используете результат malloc;) Я не фанат написания таких вещей, как (void) printf (...), чтобы остановить выдачу предупреждений компилятором, но «должен компилироваться без каких-либо предупреждений, даже глупых» - это то, что случается во многих проектах.
Ричардб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.