4

我想知道释放()指针是否可以转换为另一种类型。例如,如果我这样做:

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 函数。

上面的代码合法吗?

4

4 回答 4

6

可能是安全的,但不能绝对保证它是安全的。

在大多数现代系统上,所有指针(至少所有对象指针)都具有相同的表示,并且从一种指针类型转换为另一种只是重新解释构成表示的位。但是 C 标准并不能保证这一点。

char *p = malloc (sizeof (int));

这为您提供了char*指向sizeof (int)数据字节的指针(假设malloc()成功。)

int *q = (int *)p;

这会将char*指针转换为int*指针。由于int大于char,因此int*指针可能需要较少的信息来指示它指向的内容。例如,在面向字的机器上,anint*可能只指向一个字,而 achar*必须包含一个字指针和一个偏移量,指示它指向字内的哪个字节。(我实际上曾在 Cray T90 这样的系统上工作过。)因此,从char*to的转换int*实际上会丢失信息。

free (q);

由于free()接受类型void*为 的参数,因此该参数q被隐式转换int*void*。语言标准不能保证将char*指针转换为int*,然后将结果转换为,与将 a直接void*转换为 a 的结果相同。char*void*

另一方面,由于malloc()总是返回一个正确对齐以指向任何类型的指针,即使在具有不同表示的系统上int*char*在这种特殊情况下也不太可能导致问题。

因此,您的代码几乎可以肯定地在您可能使用的任何系统上正常工作,并且即使在您可能从未见过的外来系统上也很有可能正常工作。

尽管如此,我还是建议编写可以轻松证明是正确的代码,方法是保存原始指针值(类型char*)并将其传递给free(). 如果需要几段文字来证明您的代码几乎可以肯定是安全的,那么从长远来看,简化您的假设可能会节省您的精力。如果您的程序中出现其他问题(相信我,一定会出现问题),最好少担心一个可能的错误来源。

您的代码的一个更大的潜在问题是您不检查是否malloc()成功。如果没有,您不会做任何会失败的事情(转换和free()调用都可以使用空指针),但是如果您引用分配的内存,您可能会遇到麻烦。

更新:

您询问您的代码是否合法;你没有问这是否是做你正在做的事情的最佳方式。

malloc()返回一个void*结果,可以通过赋值隐式转换为任何指向对象的指针类型。free()接受一个void*论点;您传递给它的任何指向对象类型的参数都将被隐式转换为void*. 这种往返转换 ( to void*)是安全的。除非你正在做某种类型的双关语(将相同的数据块解释为两种不同的类型),否则不需要任何强制转换。something_else*void*

而不是:

char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);

你可以写:

int *p = malloc(sizeof *p);
...
free(p);

请注意sizeof *p在参数 to 中的使用malloc()。这为您提供了任何p指向的大小,而无需显式引用其类型。它避免了意外使用错误类型的问题:

double *oops = malloc(sizeof (int));

编译器可能不会警告您。

于 2012-10-02T22:47:42.250 回答
3

是的,指针没有改变,转换只是编译器解释一堆位的方式。

编辑: malloc 调用返回内存中的地址,即 32(或 64)位数字。转换只告诉编译器如何解释存储在该地址的值,它是浮点数、整数、字符串等,以及当你对地址进行算术运算时,它应该插入多大的单元。

于 2012-10-02T22:43:49.767 回答
3

是的,这是合法的。free()需要一个 void 指针 ( void*),所以类型无关紧要。只要传递给的指针被malloc/realloc/calloc它返回是有效的。

于 2012-10-02T22:46:08.393 回答
0

该代码是合法的,但不是必需的。由于指针仅指向存储数据的地址,因此无需分配空间或随后释放空间。

于 2012-10-02T22:44:14.440 回答