Ответ 1
Нет, поведение не определено. Более того, код не должен компилироваться.
Во-первых, код не должен компилироваться, потому что он содержит нарушение ограничения. Выражение, которое вы передаете как операнд free
, имеет тип int
. Параметр free
имеет тип void *
. Единственный случай, когда значение int
может быть неявно преобразован в тип void *
, - это когда значение int
является интегральным константным выражением (ICE) со значением 0
. В вашем случае x
не является ICE, что означает, что он неявно конвертируется в void *
. Единственная причина, по которой ваш код компилируется, заключается в том, что по историческим причинам (для поддержки устаревшего кода) ваш компилятор спокойно игнорирует нарушение ограничений, присутствующее в вызове free(x)
. Я уверен, что если вы повысите уровень предупреждений в своем компиляторе, он будет жаловаться (по крайней мере с предупреждением). Педантичный компилятор немедленно выдает ошибку для вызова free(x)
. Попробуйте Comeau Online, например, в режиме C89/90:
"ComeauTest.c", line 6: error: argument of type "int" is incompatible with parameter
of type "void *"
free(x);
^
(Кроме того, вы не забыли включить stdlib.h
перед вызовом free
?)
Во-вторых, допустим, что код компилируется, т.е. интерпретируется компилятором как free((void *) x)
. В этом случае непостоянное интегральное значение x
преобразуется в тип указателя void *
. Результатом этого преобразования является реализация. Обратите внимание, что язык гарантирует, что, когда ICE со значением 0
преобразуется в тип указателя, результатом является нулевой указатель. Но в вашем случае x
не является ICE, поэтому результат преобразования определяется реализацией. В C нет гарантии, что вы получите нулевой указатель, преобразов целое число не ICE со значением 0
в тип указателя. В вашей реализации, вероятно, только что произошло, что (void *) x
с не-ICE x
, равным 0
, выдает значение нулевого указателя типа void *
. Это значение нулевого указателя, переданное в free
, приводит к отсутствию операции в соответствии с спецификацией free
.
В общем случае, хотя такой указатель на free
приведет к поведению undefined. Указатели, которые вы можете законным образом передать на free
, являются указателями, полученными предыдущими вызовами malloc
/calloc
/realloc
и нулевыми указателями. Ваш указатель нарушает это ограничение в общем случае, поэтому поведение undefined.
Это то, что происходит в вашем случае. Но, опять же, ваш код содержит нарушение ограничений. И даже если вы нарушите нарушение, поведение undefined.
P.S. Заметьте, BTW, что многие ответы, уже отправленные здесь, совершают ту же серьезную ошибку. Они предполагают, что (void *) x
с нулем x
предполагается создать нулевой указатель. Это абсолютно неверно. Опять же, язык не дает никаких гарантий относительно результата (void *) x
, когда x
не является ICE. (void *) 0
гарантированно является нулевым указателем, но (void *) x
с нулем x
не гарантированно является нулевым указателем.
Это описано в C FAQ http://c-faq.com/null/runtime0.html. Для тех, кто заинтересован в лучшем понимании того, почему это так, может быть хорошей идеей прочитать весь раздел о нулевых указателях http://c-faq.com/null/index.html