C/C++:指针算术

Moh*_*bil 12 c c++ math pointers pointer-arithmetic

我正在阅读Pointer Arithmetic中的一些内容,我遇到了两件我无法理解的事情,也不知道它的用途

address_expression - address_expression
Run Code Online (Sandbox Code Playgroud)

并且

address_expression > address_expression
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释一下,它们是如何工作的以及何时使用它们.

编辑:

我想说的是,如果我只取两个地址并减去它们,它们会产生什么

如果我拿两个地址并比较它们的结果或基于的比较

编辑:我现在明白了减去地址的结果,但比较地址我仍然没有得到它.

我理解1 <2,但是地址如何比另一个更大,他们在比较什么

Eri*_*hil 26

这里有几个答案说明指针是数字.这不是C标准指定的指针的准确描述.

在很大程度上,您可以将指针视为数字,并将其视为内存中的地址,前提是(a)您理解指针减法将差异从字节转换为元素(被减去的指针类型),以及(b)您了解此模型中断的限制.

以下使用1999 C标准(ISO/IEC 9899,第二版,1999-12-01).我希望以下内容比请求者要求的更详细,但是,鉴于此处的一些错误陈述,我判断应该给出准确和准确的信息.

根据6.5.6第9段,您可以减去指向同一数组元素的两个指针或者超过数组最后一个元素的指针.所以,如果你有int a[8], b[4];,你可以从指向[2]的指针中减去指向[5]的指针,因为[5]和[2]是同一数组中的元素.您也可以从指向[8]的指针中减去指向[5]的指针,因为[8]是一个超过数组最后一个元素的指针.(a [8]不在数组中; a [7]是最后一个元素.)你不能从指向b [2]的指针中减去指向[5]的指针,因为a [5]不在与b [2]相同的数组.或者,更准确地说,如果进行这样的减法,则行为未定义.请注意,它不仅仅是未指定的结果; 你不能指望你会得到一些可能无意义的数字:行为是未定义的.根据C标准,这意味着C标准没有说明结果会发生什么.您的程序可以给您一个合理的答案,或者它可以中止,或者它可以删除文件,所有这些后果都符合C标准.

如果执行允许的减法,则结果是从第二个指向元素到第一个指向元素的元素数.因此,a[5]-a[2]是3,并且a[2]-a[5]是-3.无论什么类型,a都是如此.需要C实现来将距离从字节(或它使用的任何单位)转换为适当类型的元素.如果a是每个八个字节的双精度数组,那么a[5]-a[2]对于3个元素则为3.如果a是每个字节的char数组,那么a[5]-a[2]对于3个元素则为3.

为什么指针不仅仅是数字?在某些计算机上,尤其是旧计算机上,寻址内存更复杂.早期的计算机有小的地址空间.当制造商想要制造更大的地址空间时,他们还希望保持与旧软件的一些兼容性.由于硬件限制,它们还必须实现各种用于寻址存储器的方案,并且这些方案可能涉及在存储器和磁盘之间移动数据或者改变处理器中的特殊寄存器以控制地址如何被转换为物理存储器位置.对于在这样的机器上工作的指针,它们必须包含更多信息,而不仅仅是一个简单的地址.因此,C标准不仅将指针定义为地址,而且让您使用它们进行算术运算.仅定义了合理数量的算术,并且需要C实现来提供必要的操作以使该算术工作,但不再需要.

即使在现代机器上,也可能会出现并发症.在Digital的Alpha处理器上,指向函数的指针不包含函数的地址.它是函数描述符的地址.该描述符包含函数的地址,它包含正确调用函数所需的一些附加信息.

关于关系运算符,例如>,C标准在6.5.8第5段中说,你可以比较你可以减去的相同指针,如上所述,你也可以比较指向聚合对象成员的指针(a结构或联合).指向数组成员(或其结束地址)的指针以预期方式进行比较:指向较高索引元素的指针大于指向较低索引元素的指针.指向同一联盟的两个成员的指针比较相等.对于指向结构的两个成员的指针,指向稍后声明的成员的指针大于指向先前声明的成员的指针.

只要您保持在上述约束之内,那么您可以将指针视为数字,即内存地址.

通常,C实现很容易提供C标准所需的行为.即使计算机具有复合指针方案(例如基址和偏移量),通常数组的所有元素都将使用相同的基址,并且结构的所有元素将使用相同的基址.因此编译器可以简单地减去或比较指针的偏移部分,以获得所需的差异或比较.

但是,如果在这样的计算机上减去指向不同数组的指针,则会得到奇怪的结果.由基址和偏移形成的位模式可能比另一个指针看起来更大(当被解释为单个整数时),即使它指向存储器中的较低地址.这是您必须遵守C标准规定的一个原因.

  • 非常好的答案:我可以说读完这篇文章后我学到了一些东西。您确实成功地提供了具体且有启发性的推理,说明为什么它不像“地址只是数字”那么简单,以及为什么规范在这一点上是特定的(或者更确切地说,将其留给实现)。我将编辑我自己的答案以使其更好,或完全删除它。谢谢 (2认同)
  • 当两个指针相减时,结果类型是什么?一个“ptrdiff_t”?一个“uintptr_t”?还有别的事吗? (2认同)
  • @jww:两个指针相减的结果具有类型“ptrdiff_t”。 (2认同)

oua*_*uah 22

指针减法产生相同类型的两个指针之间的数组元素的数量.

例如,

int buf[10] = /* initializer here */;

&buf[10] - &buf[0];  // yields 10, the difference is 10 elements
Run Code Online (Sandbox Code Playgroud)

指针比较.例如,对于该>关系运算符:在>操作的产率1,如果在左手侧上的尖的数组元素或结构构件是在右手侧上的尖的数组元素或结构构件和后它产生0否则.记住数组和结构是有序序列.

 &buf[10] > &buf[0];  // 1, &buf[10] element is after &buf[0] element
Run Code Online (Sandbox Code Playgroud)

  • `-` 和 `&gt;` 仅适用于指向同一数组的指针。将它们用于其他任何事情都是未定义的行为。 (2认同)
  • "在同一类型的两个指针之间." 不是一个字符串足够的条件.它应该是"在相同类型的两个指针和相同数组的元素之间(或1个通道)." (2认同)

pad*_*ddy 5

两个指针地址相减返回该类型元素的数量。

因此,如果您有一个整数数组和两个指针,减去这些指针将返回之间的 int 值数,而不是字节数。与字符类型相同。所以你需要小心这一点,尤其是当你使用字节缓冲区或宽字符时,你的表达式正在计算正确的值。如果您需要基于字节的缓冲区偏移量来存储不使用单个字节的内容(int、short 等),您需要首先将指针转换为 char*。

  • 小细节:对于 `char` 类型,减法总是计算字节数,因为 C 标准将 `char` 定义为一个字节。 (3认同)
  • 此外,重要的是要注意,如果`p1 - p2` 和`p1 &lt; p2` 的结果是未定义的,如果这两个指针不指向同一个超级对象中的子对象(同一个数组中的元素)。 (3认同)
  • @DietrichEpp 这有点误导,因为字节的 C 定义不一定是八位字节。 (2认同)