Lum*_*mox 3 c pointers integer-overflow
这是代码:
#include <stdio.h>
int main()
{
int i = 3;
int *p = &i;
p - (p - 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器(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);
^
Run Code Online (Sandbox Code Playgroud)
在我的机器上获得了正确的结果1.
为什么?
这是因为指针地址是无符号整数但是ptrdiff_t是一个有符号的int并且无法处理那些大数字?
我看到了
p - (p);
Run Code Online (Sandbox Code Playgroud)
和
p - (p + 1);
Run Code Online (Sandbox Code Playgroud)
不要引起溢出.
我试图了解幕后发生的事情.这是我关于stackoverflow的第一个问题,如果我的问题可以改进,请告诉我.
指针算术不是整数算术.它是根据数组元素的地址定义的.如果p指向数组的元素,则p-1指向同一数组的前一个元素.如果该元素不存在,则减法具有未定义的行为.
出于指针运算的目的,单个对象被视为1元素数组.指针可以指向刚好超过数组的末尾,但是这样的指针可能不会被解除引用.
int i = 3;
int *p = &i;
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好; p指向i.
p - (p - 1);
Run Code Online (Sandbox Code Playgroud)
评估p - 1具有未定义的行为.没有正确的结果.
通常,编译器不生成用于在运行时检查指针算法的有效性的代码.在典型的实现中,上面将产生"预期"的结果1.编译器甚至可能1在编译时用文字替换表达式- 但是在进行优化所需的分析时,它可能会注意到行为未定义并警告您.
至于为什么你得到那个特定的消息,这是一个关于你的编译器的问题,恰好是gcc.我没有用gcc 4.7.2得到这个消息,但我确实得到了4.8.0和4.9.0.(命令
gcc --version
Run Code Online (Sandbox Code Playgroud)
告诉你你正在使用哪个版本).gcc打印一些警告消息是正确的,但该特定消息不正确,因为没有执行整数运算."整数溢出"消息是gcc中的一个错误,它也会导致它为有效代码打印虚假警告.我已经提交了一个错误报告,目前预计将在4.8.4版本中修复.
p - (p);
Run Code Online (Sandbox Code Playgroud)
这是有效的(但括号是不必要的).减去两个指针产生它们指向的数组元素之间的元素距离.如果它们没有指向同一个数组,或者只是指向它的末尾,则行为是未定义的.p - p,鉴于它p是一个有效的指针,只是0(类型ptrdiff_t).
p - (p + 1);
Run Code Online (Sandbox Code Playgroud)
也有效. p + 1超过结束点i,这是允许的.减法-1再次产生类型ptrdiff_t.
推荐阅读:comp.lang.c FAQ的第4节(指针)和第6节(数组和指针).