Нет, поведение не определено. Более того, код не должен компилироваться.
Во-первых, код не должен компилироваться, поскольку он содержит нарушение ограничения. Выражение, которое вы передаете в качестве операнда 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
с non-ICE x
, равным 0
, создает нулевое значение указателя типа void *
. Это значение нулевого указателя при передаче free
приводит к неработоспособности в соответствии со спецификацией free
.
В общем случае передача такого указателя на free
приведет к неопределенному поведению. Указатели, которые вы можете легально передать free
, это указатели, полученные при предыдущих вызовах malloc
/ calloc
/ realloc
, и нулевые указатели. Ваш указатель нарушает это ограничение в общем случае, поэтому поведение не определено.
Это то, что происходит в вашем случае. Но, опять же, ваш код содержит нарушение ограничения. И даже если вы переопределите нарушение, поведение не определено.
P.S. Обратите внимание, что многие ответы, уже размещенные здесь, допускают ту же серьезную ошибку. Они предполагают, что (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