7

通过 a 访问指针类型是否合法void **

我查看了关于指针别名的标准引用,但我仍然不确定这是否是合法的 C:

int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);

微不足道的例子,但它适用于我所看到的更复杂的情况。

似乎这不合法,因为我int *通过类型不是int *or的变量访问char *。对此我无法得出一个简单的结论。

有关的:

4

3 回答 3

4

No.void **有一个特定的类型(指向空指针的指针)。即指针的基础类型是“指向无效的指针”

存储指向 int 的指针时,您没有存储类似指针的值。需要演员表是一个强有力的指标,您正在做的事情不是标准定义的行为(事实并非如此)。然而,有趣的是,您可以使用常规void*的进出,它会表现出定义的行为。换句话说,这:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *array;
    void *vp = &array;
    int **parray = vp;
    *parray = malloc(sizeof(int)*10);
}

是合法的。如果我删除演员表并使用apple llvm 4.2(clang),您的原始示例甚至不会编译,这正是由于指针类型不兼容,即您问题的主题。具体错误是:

“用'int **'类型的表达式初始化'void **'的不兼容指针类型”

理所当然地。

于 2013-08-31T19:26:16.633 回答
2

指向不同类型的指针可以有不同的大小。

您可以将指向任何类型的指针存储到 a 中void *,然后您可以将其恢复回来,但这仅意味着 avoid *必须足够大以容纳所有其他指针。

相反,一般来说,不允许处理持有int *类似于它的变量的变量。void *

另请注意,进行强制转换(例如,强制转换为int *的结果malloc)与处理包含 a 的内存区域完全不同,int *因为它包含 a void *。在第一种情况下,如果需要,编译器会被告知转换,而在第二种情况下,您向编译器提供了错误信息。

然而,在 X86 上,它们的大小通常相同,如果您只是使用指向数据的指针(尽管指向函数的指针可能不同),那么您是安全的。

关于通过 avoid *或 a完成的任何写操作的别名char *可以改变任何对象,因此编译器必须尽可能考虑别名。但是,在您的示例中,您正在编写一个void **(不同的东西),编译器可以自由地忽略对int *.

于 2013-08-31T19:16:50.803 回答
0

您的代码可能在某些平台上工作,但它不可移植。原因是 C 没有指向指针类型的通用指针。在标准的情况下,void *明确允许它与其他指向完整/不完整类型的指针之间进行转换,但void **. 这意味着在您的代码中,编译器无法知道 的值是否*vp是从 以外的任何类型转换的void *,因此除了您自己显式转换的转换之外,无法执行任何转换。

考虑这段代码:

void dont_do_this(struct a_t **a, struct b_t **b)
{
    void **x = (void **) a;
    *x = *b;
}

编译器不会抱怨该行中的隐式转换 from to b_t *,即使该行试图将指向 a 的指针放在只应放置指针的位置。错误实际上出在上一行,它将“指向可以放置指针的位置的指针”转换为“指向可以放置任何指针的位置的指针”。这就是不可能进行隐式强制转换的原因。有关指向算术类型的指针的类似示例,请参阅C 常见问题解答void **x = *bb_ta_ta_t

那么,即使它关闭了编译器警告,您的强制转换也是危险的,因为并非所有指针类型都可能具有相同的内部表示/大小(例如void **int *)。为了使您的代码在所有情况下都能正常工作,您必须使用中间体void *

int *array;
void *varray = array;
void **vp = &varray;
*vp = malloc(sizeof(int) * 10);
于 2013-08-31T20:16:27.460 回答