通过 a 访问指针类型是否合法void **
?
我查看了关于指针别名的标准引用,但我仍然不确定这是否是合法的 C:
int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);
微不足道的例子,但它适用于我所看到的更复杂的情况。
似乎这不合法,因为我int *
通过类型不是int *
or的变量访问char *
。对此我无法得出一个简单的结论。
有关的:
通过 a 访问指针类型是否合法void **
?
我查看了关于指针别名的标准引用,但我仍然不确定这是否是合法的 C:
int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);
微不足道的例子,但它适用于我所看到的更复杂的情况。
似乎这不合法,因为我int *
通过类型不是int *
or的变量访问char *
。对此我无法得出一个简单的结论。
有关的:
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 **'的不兼容指针类型”
理所当然地。
指向不同类型的指针可以有不同的大小。
您可以将指向任何类型的指针存储到 a 中void *
,然后您可以将其恢复回来,但这仅意味着 avoid *
必须足够大以容纳所有其他指针。
相反,一般来说,不允许处理持有int *
类似于它的变量的变量。void *
另请注意,进行强制转换(例如,强制转换为int *
的结果malloc
)与处理包含 a 的内存区域完全不同,int *
因为它包含 a void *
。在第一种情况下,如果需要,编译器会被告知转换,而在第二种情况下,您向编译器提供了错误信息。
然而,在 X86 上,它们的大小通常相同,如果您只是使用指向数据的指针(尽管指向函数的指针可能不同),那么您是安全的。
关于通过 avoid *
或 a完成的任何写操作的别名char *
可以改变任何对象,因此编译器必须尽可能考虑别名。但是,在您的示例中,您正在编写一个void **
(不同的东西),编译器可以自由地忽略对int *
.
您的代码可能在某些平台上工作,但它不可移植。原因是 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 = *b
b_t
a_t
a_t
那么,即使它关闭了编译器警告,您的强制转换也是危险的,因为并非所有指针类型都可能具有相同的内部表示/大小(例如void **
和int *
)。为了使您的代码在所有情况下都能正常工作,您必须使用中间体void *
:
int *array;
void *varray = array;
void **vp = &varray;
*vp = malloc(sizeof(int) * 10);