我想知道free()指针是否可以转换为另一种类型。 例如,如果我这样做:
char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);
我没有收到关于gcc(-Wall)的警告。
在linux上,free上的手册页说,在malloc(),calloc()或realloc()没有返回的指针上调用free是违法的。但是如果指针被转换为中间的另一种类型会发生什么呢?
我问这个因为我读到C标准不要求不同的指针类型(例如int *和char *)具有相同的大小,我不明白这是如何可能的,因为它们都需要可以转换为void *用于调用malloc / free函数。
以上代码是否合法?
答案 0 :(得分:6)
可能是安全,但并非绝对保证是安全的。
在大多数现代系统中,所有指针(至少所有对象指针)具有相同的表示,并且从一种指针类型转换为另一种指针类型只是重新解释构成表示的位。但C标准并不能保证这一点。
char *p = malloc (sizeof (int));
这为您提供char*
指向sizeof (int)
字节数据的指针(假设malloc()
成功。)
int *q = (int *)p;
这会将char*
指针转换为int*
指针。由于int
大于char
,int*
指针可能需要更少的信息来指示它指向的内容。例如,在面向单词的机器上,int*
可能只指向一个单词,而char*
必须包含一个单词指针和一个偏移量,指示它指向的单词中的哪个字节。 (我实际上已经开发了一个系统,Cray T90,就像这样工作。)所以从char*
到int*
的转换实际上可能会丢失信息。
free (q);
由于free()
采用void*
类型的参数,因此参数q
会从int*
隐式转换为void*
。语言标准无法保证将char*
指针转换为int*
,然后将结果转换为void*
,与您直接转换char*
的结果相同到void*
。
另一方面,由于malloc()
始终返回一个指针,该指针已正确对齐以指向任何类型,即使在int*
和char*
具有不同表示的系统上,也不太可能在这种特殊情况下引起问题。
因此,您的代码几乎肯定可以在您可能正在使用的任何系统上正常工作,并且即使在您可能从未见过的异国情调的系统上也很可能正常工作。
尽管如此,我建议通过保存原始指针值(类型为char*
)并将其传递给free()
来编写可以轻松演示正确的代码。如果需要几段文字来证明您的代码几乎肯定是安全的,那么从长远来看,简化您的假设可能会节省您的工作量。如果您的程序出现其他问题(相信我,会有所作为),最好不要担心错误的来源。
您的代码更大的潜在问题是您不检查malloc()
是否成功。你没有做任何会失败的事情(如果它没有转换和free()
调用没有空指针),但如果你参考你分配的内存,你可能会遇到麻烦。
<强>更新强>
您询问您的代码是否合法;你没有问这是否是做你正在做的事情的最佳方式。
malloc()
返回void*
结果,可以通过赋值将其隐式转换为任何指向对象的指针类型。 free()
采用void*
参数;传递给它的任何指向对象的类型参数都将隐式转换为void*
。这种往返转化(void*
到something_else*
到void*
)是安全的。除非你正在做某种类型的惩罚(将相同的数据块解释为两种不同的类型),否则不需要任何类型的转换。
而不是:
char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);
你可以写:
int *p = malloc(sizeof *p);
...
free(p);
请注意在sizeof *p
的参数中使用malloc()
。这为您提供了p
点的大小,而无需明确引用其类型。它避免了意外使用错误类型的问题:
double *oops = malloc(sizeof (int));
编译器可能不会警告你。
答案 1 :(得分:3)
是指针没有改变,转换只是编译器解释一堆位的方式。
edit:malloc调用返回内存中的地址,即32(或64)位数。 强制转换只告诉编译器如何解释存储在该地址的值,它是浮点数,整数,字符串等,当你对地址进行算术时,它应该介入多大的单位。
答案 2 :(得分:3)
是的,这是合法的。 free()
采用void指针(void*
),因此类型无关紧要。只要传递的指针由malloc/realloc/calloc
返回,它就是有效的。
答案 3 :(得分:0)
代码是合法的,但没有必要。由于指针仅指向存储数据的地址,因此无需分配空间或随后将其释放。