这是代码:
#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的第一个问题,如果我的问题可以改进,请告诉我。
指针运算不是整数运算。它是根据数组元素的地址定义的。如果< 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节(数组和指针)。