【问题标题】:Why can I not do arithmetic on a cast of a void pointer?为什么我不能对 void 指针的类型进行算术运算?
【发布时间】:2014-06-02 19:42:49
【问题描述】:
void foo(void *ptr, int numBytes)
{
    (char*)ptr += numBytes;
}

这不能在 C 中编译。我知道替代方案。但是为什么这不起作用?有什么问题?

【问题讨论】:

  • 5 += 7 失败的原因相同。
  • 因为你没有使用 GCC。更准确地说,C 标准禁止它,因为指向的事物的大小是未知的,并且指针运算取决于对象的大小。您也不能增加函数指针。 GCC 确实允许在 void * 上进行算术运算(为此将其视为与 char * 的同义词),但它是标准的扩展,并且更经常出于意外而不是有意使用。避免在 void *! 上进行算术运算!
  • 实际上,我之前的评论——谢天谢地是评论——大多与问题无关;它详细说明了为什么 ptr += numBytes; 不被 GCC 以外的编译器接受(并且可能在其 GCC 兼容模式下发出叮当声),而不是为什么强制转换不起作用。信息有效,但略有偏离目标。

标签: c


【解决方案1】:

问题

问题在于(char*)ptr 不会产生一个左值,这意味着该值不能被修改——人们可以将它看作是转换的临时结果,转换会产生一个rvalue 类型为char*

这在语义上与下面的示例相同,强制转换产生一个临时值,不能为这样的值分配新值。

int x = 123;

(float)x += 0.12f; /* (1), illegal                                     */
                   /*  ^-- sementically equivalent to `123.f += 0.12f` */

解决方案

在您的问题中,您已经说过您已经知道解决此问题的方法,但我想明确编写解决方案,以展示即使强制转换产生不可修改的值,如何修改 ptr 的值。

  1. 将你的指针地址设为void
  2. 将此地址转换为 指向 char 指针的指针
  3. 取消引用该指针,生成一个指向字符的指针
  4. 修改这个产量左值,就好像原来的void*char*类型

*((char**)&ptr) += numbytes; // make `ptr` move forward `numbytes`

( 注意:解引用指针时会得到一个左值,否则无法更改指向的值位于存储在指针中的地址。)

【讨论】:

    【解决方案2】:

    那是因为

    (char*)ptr 不是左值。

    试试这个:

    void foo(void *ptr, int numBytes)
    {
        char* p = (char*)ptr;
        p += numBytes;
    }
    

    更新

    各种值类型的简要说明可以在cppreference.com 找到。这讨论了 C++ 中的值类型,但核心思想转化为 C。

    出于本次讨论的目的,

    左值是标识非临时对象或非成员函数的表达式。

    您可以获取左值的地址并分配给不同的值。

    例子:

    int i;
    int* p = &i;
    i = 20;
    

    相比之下,

    prvalue(“纯”右值)是标识临时对象(或其子对象)的表达式,或者是不与任何对象关联的值。

    文字42 是一个右值。你不能这样做:

    int* p = &42;
    42 = 53;
    

    在这一行,

        char* p = (char*)ptr;
    

    左值 (p) 是从 (char*)ptr 创建的。因此,可以使用:

        p += numBytes;
    

    【讨论】:

    • 您能否提供更多详细信息?从初学者的角度来看,两者似乎相同。看起来你使用了一个临时的中间值,它神奇地起作用了。
    • 这个答案中有一个指向 C++ 语言参考的误导性链接,它还提到了 C 中不存在的“成员函数”。不要混合或让其他人混淆 C 和 C++,这是有害的.
    【解决方案3】:

    = 的左侧,您需要一个lvalue。但是(char*)ptr 不是左值。

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 2011-06-30
      • 2021-02-14
      • 2016-09-25
      • 1970-01-01
      • 2013-06-12
      相关资源
      最近更新 更多