通过void **
访问指针类型是否合法?
我查看了指针别名的标准引用,但我仍然不确定这是否是合法的C:
int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);
琐碎的例子,但它适用于我所看到的更复杂的情况。
由于我通过类型不是int *
或int *
的变量访问char *
,因此似乎不合法。我不能就此得出一个简单的结论。
相关:
答案 0 :(得分:4)
没有。 void **
具有特定的类型(指向指向void的指针)。即指针的基础类型是“指向虚空的指针”
存储指向int的指针时,不存储like-pointer值。需要强制转换是一个强有力的指标,你所做的不是标准的定义的行为(事实并非如此)。然而,有趣的是,可以使用常规的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),原始示例甚至不会编译,这恰好归因于不兼容的指针类型,即您问题的主题。具体错误是:
“不兼容的指针类型初始化'void **',表达式为'int **'”
并且理所当然。
答案 1 :(得分:2)
指向不同类型的指针可以有不同的大小。
您可以将指向任何类型的指针存储到void *
中,然后您可以将其恢复,但这意味着void *
必须足够大以容纳所有其他指针。
通常,不允许处理持有int *
的变量,而不是像void *
这样的变量。
另请注意,执行转换(例如,转换为int *
malloc
的结果)与处理包含int *
的内存区域完全不同,例如它包含void *
1}}。在第一种情况下,编译器会在需要时通知转换,而在第二种情况下,您将向编译器提供错误信息。
在X86上,它们通常具有相同的大小,如果您只是使用指向数据的指针,那么您就是安全的(但是指向函数的指针可能会有所不同)。
关于通过void *
或char *
完成的任何写操作的别名可以改变任何对象,因此编译器必须尽可能考虑别名。
然而,在您的示例中,您正在编写void **
(另一种情况)并且编译器可以自由地忽略对int *
的潜在别名效果。
答案 2 :(得分:0)
您的代码可能适用于某些平台,但它不可移植。原因是C没有指向指针类型的通用指针。在void *
的情况下,标准明确允许它与其他指向完整/不完整类型的指针之间的转换,但void **
不是这种情况。这意味着在您的代码中,编译器无法知道*vp
的值是否从void *
以外的任何类型转换,因此除了您明确的转换之外无法执行任何转换施展自己。
考虑以下代码:
void dont_do_this(struct a_t **a, struct b_t **b)
{
void **x = (void **) a;
*x = *b;
}
编译器不会抱怨b_t *
行中从void *
到*x = *b
的隐式强制转换,即使该行试图将指针指向b_t
在一个只有a_t
指针的地方。错误实际上是在上一行中,它将“指向a_t
指针的地方的指针”转换为“指向任何指针的地方的指针”。这就是没有隐式演员的原因。有关指向算术类型的指针的类似示例,请参阅C FAQ。
然后,即使它关闭了编译器警告,你的演员也很危险,因为并非所有指针类型都可能具有相同的内部表示/大小(例如void **
和int *
)。要使代码在所有情况下都能正常工作,您必须使用中间void *
:
int *array;
void *varray = array;
void **vp = &varray;
*vp = malloc(sizeof(int) * 10);