【问题标题】:Is there a defined way to do pointer subtraction in C11?在 C11 中是否有定义的方法来进行指针减法?
【发布时间】:2016-07-18 16:44:28
【问题描述】:

有没有办法在 C11 中从另一个指针中减去一个指针并始终定义结果?

标准规定如果结果不能表示为类型 ptrdiff_t,则行为未定义。

我对依赖静态断言的解决方案持开放态度,这些断言有望在现代通用 32 位或 64 位环境中传递合理的实现。我想避免依赖于任何类型的运行时检查的解决方案。

如果指向的类型的大小大于 1,我可以静态断言 size_t 和 ptrdiff_t 具有相同数量的非填充位。这个部分解决方案依赖于我不确定的两件事,因此对此的任何反馈都将提供部分答案:

  1. 在现代通用 32 位或 64 位环境的合理实现中,可以预期 ptrdiff_t 最多比 size_t 少一个值位。

  2. 我对标准的理解是正确的,因为定义了两个指向大小大于 1 的对象的指针之间的差异,即使如果将指针强制转换为字符指针,相同的差异也未定义。这种理解似乎与委员会草案中的脚注 106 不一致,但我的理解是脚注不是规范性的。

【问题讨论】:

  • 目的是什么?您可以随时将指针指向uintptr_t 和朋友...
  • 总是做这样的演员很麻烦,但更重要的是,这并不能解决问题。指针表示为 uintptr_t 类型的方式没有定义,因此减去转换版本不会产生明确定义的结果。
  • @EugeneSh。你可以,但价值没有意义。 C 只保证来回转换不会改变值。
  • 指针差异本身也不是很有意义。再说一遍。具体是什么问题?
  • 唯一的解决办法是将字符数组的大小限制为SIZE_MAX / 2。这将需要运行时检查,除非每个字符数组的大小在编译时都是已知的。坦率地说,这个问题没有满足您要求的解决方案。

标签: c pointers undefined-behavior c11 pointer-arithmetic


【解决方案1】:

按照标准

如果两个指针都指向同一个对象,则只能减去指针,其中包括“one-past-the-end”指针。

减去uintptr_tintptr_t 不一定有意义,因为再一次,根据标准,没有特定的方式必须定义从指针到整数的转换。特别是,

  • 考虑分段内存模型中的远指针,其中可能有不止一种方式来表示给定地址(段 + 偏移,例如,在 x86 上)。

  • 考虑带有被处理器忽略的位的指针。 (例如,摩托罗拉 68000 处理器,它有 32 位指针,但忽略高 8 位。)

因此,不幸的是,根据标准,没有办法做到这一点。

记住: size_t 是对象的最大尺寸。它不是您的地址空间的大小。 size_t 的范围小于 uintptr_t 和朋友是完全合法的。与ptrdiff_t 相同:ptrdiff_t 的范围小于uintptr_t 是完全合法的。例如,想象一个分段内存模型,您不能分配比段更大的任何东西,在这种情况下,size_tptrdiff_t 可能能够表示段的大小,但不能表示地址空间的大小。

按惯例

在您使用的计算机(现代 32 位和 64 位计算机)上,uintptr_t 将只包含指针地址。减去。这是实现定义但不是未定义的行为。

除非它们指向同一个对象,或者指向经过该对象的地址,否则不要在不强制转换的情况下减去原始指针。当您使用指针算法时,编译器可以并且将会做出别名假设。不仅你的程序“技术上”是错误的,而且编译器在这里产生错误代码的历史由来已久。

关于指向同一个对象的指针究竟意味着什么,现在有一些争论,但这个争论在我上次检查时没有解决。

【讨论】:

  • 一个非常好的答案。
  • 谢谢,这完全回答了我的问题。
  • 我已经尝试在你提到的关于指向同一个对象的含义的辩论中找到一些东西,我有兴趣了解更多关于它的信息,是否有关于它的帖子或者你可以指出我的东西?
  • @Kyle:我现在找不到。但核心讨论是关于int x[2][2]; 之类的情况以及&x[0][0] + 2 是否等同于&x[1][0]
  • 许多具有 16 位“int”的平台允许最大 65535 字节的对象也可能一文不值。在p2 = p1+24576+24576; 之后给定char *p1,*p2;,不同的p2-p1 通常会产生-16384(而不是49152),但是将-16384 添加到p1 会产生p2。
猜你喜欢
  • 1970-01-01
  • 2011-12-29
  • 2015-10-03
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2012-07-23
相关资源
最近更新 更多