C的一个熟悉功能是void*
可以分配给任何指针变量或从任何指针变量分配。在C1的标准文档草案N1570中,该文档在6.3.2.3 Pointers
中指定:
指向void的指针可以转换为任何对象类型的指针,也可以将其转换为任何对象类型的指针。指向任何对象类型的指针都可以转换为void指针,然后再返回;结果应等于原始指针。
但是6.2.7 Compatible type and composite type
说
所有引用相同对象或函数的声明均应具有兼容的类型;否则,行为是不确定的。
据我所知,该部分不说void*
与其他指针类型兼容。所以:
int x = 5;
int *xp = &x;
void *vp = xp;
根据传统和6.3.2.3
预期是完全有效的,但6.2.7
似乎是未定义的行为。
我想念什么?
答案 0 :(得分:4)
关键字:所有声明 ...
int x = 5;
int *xp = &x;
void *vp = xp;
这是三个声明,分别声明三个独立的对象:x
,xp
和vp
。
您引用的部分意思是如果一个文件说
extern int foo;
另一个文件说
extern double *foo;
该行为未定义,因为foo
已被声明两次,类型不同。
答案 1 :(得分:1)
Q:但是,据我所知,该部分并没有说
void*
与其他指针类型///兼容 ...根据传统和6.3.2.3完全有效,但按照6.2.7似乎是未定义的行为。
6.2.7并没有说太多,而是指向6.7.6.1指针声明的进一步阅读,在这里我们可以找到相关的部分:
要使两个指针类型兼容,则两者必须具有相同的限定条件,并且都应是指向兼容类型的指针。
因此,void*
与int*
不兼容,因为void
与int
不兼容。它们可能会指向兼容类型,而您可以在它们之间自由地转换。
您发布的代码很好,因为它仅与指向的类型有关。由于指针类型不兼容而导致的未定义行为的示例可能是这样:
void* v;
int* p = *(int**)&v;
这里,指针本身的地址被强制转换为不兼容的类型。它实际上是void**
类型,但是程序员告诉编译器将其视为int**
,然后像读取int*
一样读取内容。形式上,我们通过“左值访问”读取对象,该类型与存储在该位置的对象不兼容。
尽管在实践中,由于void*
必须在不丢失信息的情况下与其他对象指针类型进行相互转换,所以几乎可以肯定它的大小和表示形式与对象指针相同。尽管C标准不能保证,但是正式威胁它为另一种类型是未定义的行为。
这与对象和strict aliasing的有效类型的C概念有关。