C:两个void指针的区别是什么类型?

C: what type is the difference of two void pointers?

如果我减去两个空指针,我得到指针位置之间的相对距离(以字节为单位)(至少在我的测试系统上是这样)。我应该使用什么类型来存储结果,以便它与 64 位系统兼容? size_t 是正确的类型还是很长?

背景:我们需要检查给定的空指针是否可以安全地用作双指针。我们曾经将指针转换为 int 并检查低三位是否为零,但是我们当前的编码标准不再允许将指针转换为整数类型。我正在考虑计算 void 指针和 NULL 指针之间的差异,并检查该差异是否可以被 8 整除。假设 NULL 指针总是 8 字节对齐?

来自 C11, 6.5.6 Additive operators /9(我的斜体):

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header.

根据该部分,从指针中减去 NULL 在技术上也是未定义的行为,因为 NULL 绝不能被视为指向同一数组或超出它的元素的指针。指针减法实际上仅限于获取同一数组中两个元素之间的索引差异。

所以你可能想重新考虑你正在做的这个检查,特别是考虑到双精度数实际上不需要八个字节长,即使是,标准中也没有要求它在八字节边界上对齐。

我更倾向于在函数的文档中声明传递的值必须是有效的 double 指针,并且如果函数的用户违反了该约定,则所有赌注都是关闭。

If I subtract two void pointers, I get the relative distance in bytes (at least on my test system I do) between the pointer locations.

两个指针相减有严格的规定。 C11-§6.5.6:

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. [...]


what type is the difference of two void pointers?

应该是ptrdiff_t

[...] The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. [...]

C 标准中没有定义 void 指针的减法。仅当指针都指向同一个数组并且 void 指针不能指向任何数组时才定义指针减法,因为您不能拥有包含 void 元素的数组。

很可能您使用的是 gcc 或其他兼容的东西,它允许对 void 指针进行算术运算作为扩展,将其视为 char 指针。但是严格的 C 编译器不应该允许对 void 指针进行指针运算。

问题总结:

  • 您将空指针常量宏 NULL 与空指针混淆了。这是两个不同的术语。 NULL 宏始终等同于 0,但空指针可以具有任何值。

  • 也就是说,使用空指针或 NULL 宏进行指针运算没有任何意义。这样做会调用未定义的行为,因为指针必须指向同一个数组。请参阅 paxdiablo 的回答。

  • 此外,正如 Art 在回答中指出的那样,您不能对 void 指针进行任何形式的算术运算。 + 和 - 运算符指定为 (6.5.6):

    For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.

    void 指针是指向不完整类型的指针,因此如果一个或两个操作数都是 void 指针,则您的代码是无效的 C。

    请注意,GCC 有一个非标准扩展,允许空指针运算,在这种情况下,将空指针视为字节指针。如果您打算编写安全且可移植的程序,请不要使用此非标准功能。如果您希望 GCC 充当标准 C 编译器(符合标准的实现),请使用 gcc -std=c11 -pedantic-errors 进行编译。