当前位置: 首页 > 知识库问答 >
问题:

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

曹新觉
2023-03-14

这是代码:

#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个答案

颜乐
2023-03-14

指针运算不是整数运算。它是根据数组元素的地址定义的。如果< 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节(数组和指针)。

 类似资料:
  • 上述代码的实际输出是 根据我的理解,访问0x0加法器时应给出SEG故障。因为*p地址是0x0。 为什么它会起作用?有人解释一下吗?

  • 本文向大家介绍C语言中指针 int *p=0;和int *p;*p=0;和”&“的关系和区别详解,包括了C语言中指针 int *p=0;和int *p;*p=0;和”&“的关系和区别详解的使用技巧和注意事项,需要的朋友参考一下 初学者在学习C语言的时候,最头疼的可能就是指针,话不多说。让我们直接进入正题 直接上代码 直接运行,好了,程序是不是报错了?那就对了。因为此时的int *p=0实际等于in

  • 描述 (Description) 字符类[\p{L}&&[^\p{Lu}]]匹配除大写字母之外的任何字符。 例子 (Example) 以下示例显示了Unicode字符类匹配的用法。 package com.wenjiangs; import java.util.regex.Matcher; import java.util.regex.Pattern; public class UnicodeCh

  • p

    P is for peer-to-peer networking with browsers P is a small framework used to create browser-to-browser networks (as opposed to just a connection). With P, you can: Connect to other browsers using a s

  • P*

    P* (P-star)是一种网站编程语言,其中包括了常用的任务像模板处理以及数据查询。它突出的特性有用预处理语句来访问MySQL数据库;HTML模板;标准的计数,变量,函数和结构;JSON输出,GET和POST。

  • 在第一种情况下,我理解为:何时分配(或后续添加?)执行时,p被视为未声明。 但是为什么在一种方法中它是不同的呢?OK t不会被视为未初始化,因为(t=1)是在添加之前执行的。好的,t不是一个字段,但它现在也没有声明! 我能理解吗?要不我就记住这个区别? 也许这也与此有关: 为什么是2?第一个(x=1)以某种方式计算(x未声明!!!),然后返回1,现在x已经赋值了(!?)并且包含1,所以这两个测试。