Безопасен ли ptr = free(ptr), NULL?

#c #variable-assignment #comma-operator #symmetry

#c #присвоение переменной #оператор запятой #симметрия

Вопрос:

Я пишу такой код:

 #include <stdlib.h>

int main(void)
{
    void *kilobyte;
    kilobyte = malloc(1024);
    kilobyte = NULL, free(kilobyte);
    return 0;
}
  

для симметрии, что приятно. Но я никогда раньше не видел, чтобы кто-то еще использовал эту идиому, поэтому мне интересно, может ли это быть на самом деле непереносимым / небезопасным, несмотря на эту цитату из Википедии:

В языках программирования C и C оператор запятой (представленный токеном ,) является двоичным оператором, который вычисляет свой первый операнд и отбрасывает результат, а затем вычисляет второй операнд и возвращает это значение (и тип).


Редактировать: перепутал порядок. Теперь он компилируется gcc без каких-либо предупреждений.

Комментарии:

1. free не возвращает значение, поэтому строка написана в плохом стиле. Код даже не менее типизирован, используйте стандартный ideom.

2. AFAIK, оператор запятой отбрасывает free значение, которое есть void , и NULL вместо этого использует is . И меньше печатать, если ваш стиль требует последовательно присваивать указателям значение NULL после их освобождения.

3. Нет значения для отбрасывания! Вы пытались скомпилировать это, прежде чем спрашивать? Вы нашли доказательство в стандарте, что это законно или незаконно? Пожалуйста, процитируйте раздел. (о, и я попробовал с gcc).

4. если вы попытаетесь скомпилировать его, это будет результатом error: void value not ignored as it ought to be

5. Запустите свой «идеальный» код в отладчике!

Ответ №1:

Делая это:

 kilobyte = NULL, free(kilobyte);
  

У вас утечка памяти.

Вы установили kilobyte значение NULL, поэтому на какую бы память оно ни указывало, на нее больше нигде не ссылаются. Затем, когда вы это делаете free(kilobyte) , вы эффективно выполняете free(NULL) то, что не выполняет никаких операций.

Что касается free(NULL) стандарта C.

7.22.3.3 free Функция

1.

 #include <stdlib.h>
void free(void *ptr);
  

2. free Функция
освобождает пространство, на которое указывает ptr , то есть делает его доступным для дальнейшего выделения. Если ptr это нулевой указатель, никаких действий не происходит. В противном случае, если аргумент
не соответствует указателю, ранее возвращенному
функцией управления памятью, или если пространство было освобождено
вызовом free или realloc , поведение не определено.

Что касается вашего исходного кода перед редактированием:

 kilobyte = free(kilobyte), NULL;
  

Проблема в том, что = оператор имеет более высокий приоритет, чем , оператор, поэтому это утверждение эффективно:

 (kilobyte = free(kilobyte)), NULL;
  

Это пытается установить переменную void , значение которой не разрешено.

Вероятно, вы сделали отступ, чтобы сделать это:

 kilobyte = (free(kilobyte), NULL);
  

Это освобождает указатель, а затем устанавливает указатель на NULL.

Как упоминалось Олафом в комментариях, вместо того, чтобы делать все в одной строке, было бы предпочтительнее сделать это вместо:

 free(kilobyte);
kilobyte = NULL;
  

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