C - 表达式必须是可修改的左值

时间:2014-10-20 16:55:21

标签: c pointers void-pointers

我很困惑为什么我的编译器在以下情况下抛出错误:

void funcExample (void * p_Buf, uint16_t len) 
{
    uint16_t i;

    for (i = 0; i < len; i++) {
        otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue
    }
}

但是如果我在传递给otherFunc之前进行了强制转换,那很好,因为增加非void指针没有问题:

void funcExample (void * p_Buf, uint16_t len) 
{
    uint16_t i;
    uint8_t * p_Buf_8bit;

    p_Buf_8bit = (uint8_t *) p_Buf;   

    for (i = 0; i < len; i++) {
        otherFunc (p_Buf_8bit++); 
    }
}

一旦施放,空指针是否会递增?我错过了一些基本的东西吗?

4 个答案:

答案 0 :(得分:5)

在c:

中投射运算符
  

6.5.4。 p5带括号的类型名称前面的表达式转换了   表达式到命名类型。 这种结构称为演员表。 104)指定的演员   没有转换对表达式的类型或值没有影响。

     

104)强制转换不会产生左值。因此,对限定类型的强制转换具有与强制转换相同的效果。   

的不合格版本

但是一元运算符++需要一个左值,如下所述:

  

6.5.3.1。 p1前缀增量或减量运算符的操作数应具有原子的,合格的,   或不合格的真实或指针类型,,并且应该是可修改的左值。

因此你可以这样做:

p_Buf = ( uint8_t* )p_Buf + 1 ;

p_Buf是左值,( uint8_t* )p_Buf是左值。


我要注意,在你的第二个例子中,你没有演员(如你所说),但是你声明了一个uint8_t指针。然后当你在它上面使用++时,你不会执行任何强制转换(因为它具有正确的类型)并且操作有效。

答案 1 :(得分:1)

void中增加C指针是个坏主意。大多数编译器甚至不让它编译。请改用:

p_Buf = (uint8_t*)p_Buf + 1;

答案 2 :(得分:1)

@ 2501发布的答案是绝对正确的,但并不能解释为什么标准需要左值来进行后期增量。基本原因是你需要一个左值(变量或内存位置)来进行后递增来执行增量。

当您将p_Buf投射到uint8_t*类型时,您已在C中创建 rvalue 。简单来说, rvalues 表示可以传递给函数,分配给变量等的瞬态值。后递增返回原始值,然后更新存储值的变量或内存位置,并将其递增。因为它们仅在表达式的持续时间内存在,所以 rvalues 无法更新,并且后递增不能对它们进行操作。因此

的问题
    otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue

((uint8_t *)pBuf)只是一个 rvalue 表达式,没有实际的存储位置。实际上,演员表示您仅使用p_Buf的值,而不再直接使用变量p_Buf

另一方面,当您将演员表分配给变量时:

p_Buf_8bit = (uint8_t *) p_Buf;

然后变量p_Buf_8bit左值,它代表变量或内存位置。这可以后递增,使其成为C:

中完美的格式
    otherFunc (p_Buf_8bit++); 

答案 3 :(得分:0)

施法操作的结果是右值,而不是左值。 ((uint8_t *)p_Buf)++根本不是合法的C代码。