【问题标题】:Why is an error is generated when I type cast a pointer and subtract it?为什么当我键入强制转换指针并减去它时会产生错误?
【发布时间】:2020-02-04 18:02:01
【问题描述】:

为什么类型转换在这里不起作用..?

#include<stdio.h>
int main(){
   int x = 5;
   float y = 7.0;
   float *p = &y;
   int *q = &x;
   printf("p is %d\nq is %d\np - q is %d", p, q, (p - q));
   return 0;  
  }

我收到此错误invalid operands of types 'float*' and 'int*' to binary 'operator-';什么意思?

【问题讨论】:

  • 这意味着你不能从指向float的指针中减去指向int的指针,因为它们指向不同的类型。另外,无论如何减去它们有什么意义?
  • 你没有任何类型转换
  • 指针比较仅在两个指针都是指向同一个对象同一个对象末尾的一个元素时才有效,其中一个对象可能是一个数组。
  • 你想做什么?

标签: c pointers casting implicit-conversion


【解决方案1】:

该错误意味着编译器无法推断出两个操作数的公共类型,其中一个是float *,另一个是int *。这些类型之间没有隐式转换。

但在任何情况下,程序都有未定义的行为,因为至少你不能减去两个不指向同一数组元素或同一数组最后一个元素之后的内存的指针。

来自 C 标准(6.5.6 加法运算符)

9 当两个指针相减时,两个指针都指向 相同的数组对象,或数组的最后一个元素 目的;结果是两者下标的差 数组元素。

并且对函数printf 中提供的参数使用不正确的转换说明符(例如带有指针的%d)也会调用未定义的行为。

来自 C 标准(7.21.6.1 fprintf 函数)

9 如果转换规范无效,则行为是 undefined.275) 如果任何参数不是正确的类型 相应的转换规范,行为未定义。

【讨论】:

    【解决方案2】:

    我想你想减去你的指针指向的实际值。 当您对floatint 进行操作时,C 会将int 隐式转换为float

    另外,你的程序有一些问题

    • 不使用%f类型说明符打印float指针

    • 不使用* 运算符来访问指针值。

    这是你的程序,正在运行:

    #include <stdio.h>
    int main()
    {
        int x = 5;
        float y = 7.0;
        float *p = &y;
        int *q = &x;
        printf("p is %f\nq is %d\np - q is %f", *p, *q, (*p - *q));
        return 0;
    }
    

    输出:

    p is 7.000000
    q is 5
    p - q is 2.000000
    

    【讨论】:

      【解决方案3】:

      你不能像这样减去指针并在标准 C 中得到有意义的结果。

      6.5.6 Additive operators, paragraph 9 of the C11 standard:

      当两个指针相减时,两个指针都指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素;结果是两个数组元素的下标之差。

      在这种情况下,单个 intfloat 变量被视为大小为 1 的数组。

      给定

      int x = 5;
      float y = 7.0;
      float *p = &y;
      int *q = &x;
      

      尝试计算值 p - q 会导致未定义的行为。

      J.2 Undefined behavior

      在以下情况下行为未定义:

      ...

      • 减去不指向或刚好超出同一数组对象的指针

      但是,这样的代码可能不会导致问题,因为它只是减去两个整数值(虽然我没有彻底检查过),但结果不一定是有意义的:

      int x = 5;
      float y = 7.0;
      float *p = &y;
      int *q = &x;
      
      intptr_t diff = ( intptr_t ) p - ( intptr_t ) q;
      

      【讨论】:

        【解决方案4】:

        编辑:正如在 cmets 中指出的那样,减去两个 void* 指针不是正确的标准 C。如果要减去两个指针以找到它们之间的距离,正确的方法是将它们转换为适当大小的整数,然后进行整数运算。

        例如:

        printf("p is %p\nq is %p\np - q is %ld\n", p, q, ((intptr_t)p - (intptr_t)q));

        原答案:

        这意味着没有为混合类型的指针定义减号运算符。如果你想减去这两个指针,例如找出它们之间的空间量,更好的选择是将它们都转换为 void* 指针。

        此外,您应该使用 %p 说明符而不是 %d 打印指针值。

        例如:

        printf("p is %p\nq is %p\np - q is %ld\n", p, q, ((void*)p - (void*)q));

        【讨论】:

        • 更好的选择是将它们都转换为 void* 指针。 。您不能对 void * 指针进行指针运算。一些实现将其作为非便携式扩展提供。
        • 我不认为你可以在标准 C 中减去两个 void 指针,尽管我认为 gcc 允许它作为扩展。
        • void * 上的指针运算是非标准扩展(由 GCC 引入),因此 char * 更适合指针运算。 (从技术上来说,将指向不同对象的指针减去同一数组中的指针仍然是未定义的行为,但它可能只是显示地址值的差异,而不是在大多数实现中炸毁您的计算机。)
        • @Ian Abbott,如果想将指针视为数字,将它们转换为数字 (uintptr_t) 对我来说比将它们转换为 char* 更有意义。
        • @ikegami 或者更确切地说是intptr_t,因为减法的结果可能是负数。
        猜你喜欢
        • 2021-01-29
        • 2011-11-18
        • 1970-01-01
        • 2016-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-04
        • 2021-05-08
        相关资源
        最近更新 更多