【问题标题】:C: what type is the difference of two void pointers?C:两个void指针的区别是什么?
【发布时间】:2016-08-05 14:05:11
【问题描述】:

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

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

【问题讨论】:

  • “我们当前的编码标准不再允许将指针转换为整数类型。” --> 太糟糕了,你不能投到uintptr_t

标签: c pointers alignment void


【解决方案1】:

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

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

【讨论】:

  • 我们确实在使用 gcc。
  • @slingeraap 然后将其配置为适当的 C 编译器:-std=c11 -pedantic-errors。当你尝试做非标准的废话时,你会得到编译器错误。
【解决方案2】:

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

当两个指针相减时,两个指针都指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素;结果是两个数组元素的下标之差。结果的大小是实现定义的,它的类型(有符号整数类型)是ptrdiff_t<stddef.h> 标头中定义的。

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

因此,您可能需要重新考虑您正在执行的检查,特别是考虑到双精度实际上不需要 8 个字节长,即使是,标准中也没有要求它在八字节边界上对齐。

我更倾向于在你的函数的文档中声明传递的值必须是一个有效的 double 指针,如果你的函数的用户违反了该合同,那么所有的赌注都会被取消。

【讨论】:

  • 在我们的系统(基于 PowerPC)上,double 必须在 8 字节边界上对齐。我知道支票本身是不可移植的,但它仍然是必要的。
  • @slingeraap 好奇:当指针不是double 对齐时,你的代码会做什么?
【解决方案3】:

如果我减去两个 void 指针,我会得到指针位置之间的相对距离(至少在我的测试系统上)。

有一个严格的规则来减去两个指针。 C11-§6.5.6:

当两个指针相减时,两个指针都指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素;结果是两个数组元素的下标之差。 [...]


两个 void 指针的区别是什么?

应该是ptrdiff_t

[...] 结果的大小是实现定义的,它的类型(有符号整数类型)是在<stddef.h> 标头中定义的ptrdiff_t。 [...]

【讨论】:

    【解决方案4】:

    问题总结:

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

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

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

      对于加法,两个操作数都应具有算术类型,或者一个 操作数应为指向完整对象类型的指针,而另一个 应该是整数类型。

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

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

    【讨论】:

      猜你喜欢
      • 2019-12-05
      • 2010-12-16
      • 1970-01-01
      • 2016-08-01
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多