C:自动变量免费通话?
int main() { int x = 0; free(x); }
这编译并且似乎是无操作。 究竟发生了什么? 是这个行为定义的?
谢谢!
不,行为未定义。 而且,代码不应该编译。
首先,代码不应该编译,因为它包含约束违规。 作为free
的操作数传递的表达式具有int
类型。 free
的参数有void *
类型。 int
值可以隐式转换为void *
type的唯一情况是int
值是值为0
的积分常量表达式(ICE)。 在你的情况下, 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); ^
(另外,你还记得在free
电话之前加入stdlib.h
吗?)
其次,让我们假设代码编译,即编译器将其解释为free((void *) x)
。 在这种情况下,非常数整数值x
被转换为指针类型void *
。 此转换的结果是实现定义。 注意,该语言保证当值为0
的ICE转换为指针类型时,结果为空指针。 但在你的情况下, x
不是ICE,因此转换的结果是实现定义的。 在C中,无法保证通过将值为0
的非ICE整数转换为指针类型来获取空指针。 在你的实现上,可能恰好发生了(void *) x
其中非ICE x
等于0
产生类型为void *
的空指针值。 传递给free
,此空指针值会根据free
的规范产生no-op。
但是在一般情况下,将这样的指针传递给free
将导致未定义的行为。 你可以合法地传递给free
的指针是先前调用malloc
/ calloc
/ realloc
和null指针获得的指针。 在一般情况下,您的指针违反此约束,因此行为未定义。
这就是你的情况。 但是,您的代码再次包含约束违规。 即使您覆盖违规,行为也是未定义的。
PS注意,顺便说一句,这里已经发布的许多答案都犯了同样严重的错误。 他们假设(void *) x
和零x
应该产生一个空指针。 这绝对不正确。 同样,当x
不是ICE时,语言绝对不能保证(void *) x
的结果。 (void *) 0
保证为空指针,但(void *) x
与零x
不保证是空指针。
这将在C FAQ http://c-faq.com/null/runtime0.html中介绍 。 对于那些有兴趣更好地理解其原因的人来说,阅读有关空指针的整个部分可能是个好主意http://c-faq.com/null/index.html
在你的情况下,它的工作原理是因为调用free(NULL)(即free(0))是一个NOOP。 但是,如果使用0以外的任何值(NULL)调用它,则行为将是未定义的 – 崩溃和/或内存损坏可能是候选者。
编辑:正如其他人后来指出的那样,free(x)(x = 0)和free(NULL)不是一回事。 (虽然它通常为0,但NULL指针的值是实现定义的,不能依赖它。)请参阅AndreyT的答案以获得非常好的说明。
释放NULL(或0)什么都不做。 这是一个无操作。
您是否尝试过编译器的警告级别? 例如gcc -ansi -pedantic -W -Wall
报告:
tmp.c:6:警告:传递’free’的参数1使得整数指针没有强制转换
行为未定义。 不要这样做。
从free
手册页:
free()释放ptr指向的内存空间,该内存空间必须由之前调用malloc(),calloc()或realloc()返回。 否则,或者如果之前已经调用了free(ptr),则会发生未定义的行为。 如果ptr为NULL,则不执行任何操作。
在你的例子中,你实际上是在调用free(0)
,因为free
接受一个指针作为参数。 你实际上是在告诉运行时释放地址0的内存,而这个内存以前没有被malloc
分配过。
由于’0’为NULL,所以不会发生任何事情。 (感谢评论指出我的愚蠢错误)。
free()适用于动态分配的内存,即使用malloc,calloc或realloc分配的内存。 此外,它需要一个指针,你传递的是x的值。 没有理由在堆栈分配的变量上调用它,当堆栈展开并且行为未定义时将释放它们。 总是很好阅读文档。
它应该在大多数体系结构上抛出访问冲突。 好吧,它是0,所以它的工作原理,但如果它不是0,它将失败。 这是未定义的。 你不能free()
一个堆栈分配变量。
free(0); “使用NULL值调用自由函数,将无效。”
实际上,当我们释放使用内存时,它会产生影响。
这里x值为零,因此它不会产生任何问题。 如果x的值不是
在这种情况下,它可能会出现分段错误。 因为x值可能用作
记忆表示一些其他变量。