为什么不能在void指针的强制转换上做算术运算?


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

这不能在c中编译。我知道另一种选择。但为什么这不起作用呢?有什么问题吗?

问题

问题是(char*)ptr不会产生左值,这意味着该值不能修改-可以将其视为强制转换的临时结果,强制转换将产生类型为char*右值

在语义上和下面的例子是一样的,强制转换产生一个临时值,这样的值不能被赋给一个新值。

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

<

解决方案/strong>

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

  1. 指针的地址给void
  2. 将此地址转换为指向char的指针的指针,
  3. 对该指针解引用,生成一个指向char指针,
  4. 修改此yield lvalue,就像原来的void*char*类型一样

<一口>

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

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

这是因为

(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;
相比之下,

右值("pure"右值)是标识临时对象(或其子对象)或不与任何对象关联的值的表达式。

字面值42是右值。你不能这样做:

int* p = &42;
42 = 53;

本行

    char* p = (char*)ptr;

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

    p += numBytes;

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

最新更新