空指针与其他指针类型的兼容性
Void pointer compatibility with other pointer types
C 的一个熟悉的特性是 void*
可以赋值给任何指针变量或从任何指针变量赋值。在 N1570 中,C11 的标准文档草案,在 6.3.2.3 Pointers
:
中指定
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
但是6.2.7 Compatible type and composite type
说
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
然而,据我所知,该部分 不是 说 void*
与其他指针类型兼容。所以:
int x = 5;
int *xp = &x;
void *vp = xp;
预计在传统和 6.3.2.3
中完全有效,但在 6.2.7
中似乎是未定义的行为。
我错过了什么?
关键字:所有声明 ...
int x = 5;
int *xp = &x;
void *vp = xp;
这是三个声明,声明了三个独立的对象:x
、xp
和vp
。
你引用的部分的意思是,如果一个文件说
extern int foo;
另一个文件说
extern double *foo;
行为未定义,因为 foo
已声明两次,类型不同。
Q: Yet, as far as I can see, that section does not say void*
is compatible with other pointer types /--/
...perfectly valid by tradition and 6.3.2.3, but would seem to be undefined behavior by 6.2.7.
6.2.7 没有说太多,但指出进一步阅读 6.7.6.1 指针声明,在那里我们可以找到相关部分:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
所以不,void*
与 int*
不兼容,因为 void
与 int
不兼容。不过,它们可能 指向 兼容类型,您可以 在它们之间自由转换 。
您发布的代码很好,因为它只涉及 pointed-at 类型。由于 non-compatible 指针类型而导致的未定义行为的示例宁愿是这样的:
void* v;
int* p = *(int**)&v;
这里把指针本身的地址强行转换成了non-compatible类型。它实际上是 void**
类型,但程序员告诉编译器将其视为 int**
,然后读取内容就好像它是 int*
一样。正式地,我们通过与存储在该位置的对象不兼容的类型的 "lvalue access" 读取对象。
但实际上,由于 void*
必须转换 to/from 其他对象指针类型而不丢失信息,因此它几乎可以肯定具有与对象指针相同的大小和表示形式。 C 标准并不保证这一点,因此正式威胁它作为另一种类型是未定义的行为。
这与对象的有效类型和strict aliasing的C概念有关。
C 的一个熟悉的特性是 void*
可以赋值给任何指针变量或从任何指针变量赋值。在 N1570 中,C11 的标准文档草案,在 6.3.2.3 Pointers
:
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
但是6.2.7 Compatible type and composite type
说
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
然而,据我所知,该部分 不是 说 void*
与其他指针类型兼容。所以:
int x = 5;
int *xp = &x;
void *vp = xp;
预计在传统和 6.3.2.3
中完全有效,但在 6.2.7
中似乎是未定义的行为。
我错过了什么?
关键字:所有声明 ...
int x = 5;
int *xp = &x;
void *vp = xp;
这是三个声明,声明了三个独立的对象:x
、xp
和vp
。
你引用的部分的意思是,如果一个文件说
extern int foo;
另一个文件说
extern double *foo;
行为未定义,因为 foo
已声明两次,类型不同。
Q: Yet, as far as I can see, that section does not say
void*
is compatible with other pointer types /--/ ...perfectly valid by tradition and 6.3.2.3, but would seem to be undefined behavior by 6.2.7.
6.2.7 没有说太多,但指出进一步阅读 6.7.6.1 指针声明,在那里我们可以找到相关部分:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
所以不,void*
与 int*
不兼容,因为 void
与 int
不兼容。不过,它们可能 指向 兼容类型,您可以 在它们之间自由转换 。
您发布的代码很好,因为它只涉及 pointed-at 类型。由于 non-compatible 指针类型而导致的未定义行为的示例宁愿是这样的:
void* v;
int* p = *(int**)&v;
这里把指针本身的地址强行转换成了non-compatible类型。它实际上是 void**
类型,但程序员告诉编译器将其视为 int**
,然后读取内容就好像它是 int*
一样。正式地,我们通过与存储在该位置的对象不兼容的类型的 "lvalue access" 读取对象。
但实际上,由于 void*
必须转换 to/from 其他对象指针类型而不丢失信息,因此它几乎可以肯定具有与对象指针相同的大小和表示形式。 C 标准并不保证这一点,因此正式威胁它作为另一种类型是未定义的行为。
这与对象的有效类型和strict aliasing的C概念有关。