提问者:小点点

减法指针p-(p-1)如何产生整数溢出?


这是代码:

#include <stdio.h>
int main()
{
  int i = 3;
  int *p = &i;
  p - (p - 1);
  return 0;
}

编译器(gcc)警告外部减法处的整数溢出:

[user@comp c]$ gcc foo.c
foo.c: In function ‘main’:
foo.c:6:5: warning: integer overflow in expression [-Woverflow]
   p - (p - 1);
     ^

在我的机器上获得了正确的结果1。

为什么?

这是因为指针地址是无符号整数,但ptrdiff_t是有符号整数,无法处理这些大数字吗?

我看到了

p - (p);

p - (p + 1);

不要造成溢出。

我正在努力了解这里的幕后情况。这是我关于stackoverflow的第一个问题,如果我的问题可以改进,请告诉我。


共1个答案

匿名用户

指针运算不是整数运算。它是根据数组元素的地址定义的。如果< code>p指向数组的一个元素,那么< code>p-1指向同一数组的前一个元素。如果该元素不存在,则减法具有未定义的行为。

出于指针算法的目的,单个对象被视为1元素数组。一个指针可能正好指向数组的末尾,但是这样的指针不能被解引用。

int i = 3;
int *p = &i;

到目前为止,一切顺利;< code>p指向< code>i。

p - (p - 1);

评估< code>p - 1有未定义的行为。没有正确的结果。

通常,编译器不会生成代码来检查指针算术在运行时的有效性。在典型的实现中,上述结果将产生“预期”结果 1。编译器甚至可能在编译时将表达式替换为文字 1 -- 但是在进行优化所需的分析时,它可能会注意到行为未定义并警告您。

至于你为什么会收到这个特定的消息,这是一个关于你的编译器的问题,它碰巧是gcc。我在gcc 4.7.2中没有得到该消息,但我在4.8.0和4.9.0中都得到了该消息

gcc --version

告诉您正在使用哪个版本)。gcc打印一些警告消息是正确的,但该特定消息是不正确的,因为没有执行整数算术。“整数溢出”消息是gcc中的一个bug,它还导致它为有效代码打印虚假警告。我已经提交了一份bug报告,目前预计将在4.8.4版中修复。

p - (p);

这是有效的(但括号是不必要的)。两个指针的相减产生了它们所指向的数组元素之间的距离(以元素为单位)。如果它们不指向同一个数组,或者刚好超过数组的末尾,则行为是未定义的p-p</code>,如果<code>p</code>是一个有效的指针,那么它就是<code>0(类型为<code>ptrdifft)。

p - (p + 1);

也有效。p 1 点超过 i 的末尾,这是允许的。减法产生 -1,同样是类型 ptrdiff_t

推荐阅读:comp.lang.c常见问题解答的第4节(指针)和第6节(数组和指针)。