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