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

6
我很困惑为什么我的编译器在以下条件下会报错:
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++); 
    }
}

空指针被强制转换后不能递增吗?我是否忽略了某些基本知识?


这里有一个非常相似的问题:https://dev59.com/6oDba4cB1Zd3GeqPB0Lo,但并非完全相同。 - WhozCraig
4个回答

5

C语言中的类型转换操作符:

6.5.4. p5 通过在表达式前加上带括号的类型名称,可以将表达式的值转换为指定类型的值。 这种构造称为类型转换(cast)。104) 没有进行转换的类型转换对表达式的类型或值没有影响。

104) 类型转换不产生lvalue。 因此,对限定类型进行类型转换与对未限定类型进行类型转换具有相同的效果。

但是一元运算符++要求是一个lvalue,如下所述:

6.5.3.1. p1 前缀递增或递减运算符的操作数必须具有原子、限定或未限定的实数或指针类型,并且必须是可修改的lvalue。

因此,您可以执行以下操作:

p_Buf = ( uint8_t* )p_Buf + 1 ;

在这个示例中,p_Buf 是左值,而( uint8_t* )p_Buf 是右值。


请注意,在您的第二个示例中,您没有进行强制转换(正如您所说),而是声明了一个uint8_t指针。然后当您对其使用++时,您不执行任何强制转换(因为它具有正确的类型),并且操作是有效的。


你将 void 指针转换为 uint8_t,而不是将指针转换为 void - Vladyslav
@Seprum 不是的。你可能看到了一个旧版本,请刷新页面。 - 2501
感谢您的回复和标准参考。是的,在第二个中是一个分配而不是一个转换。 - jaypee

1

@2501发表的答案绝对正确,但并未解释为什么标准要求post-increment需要一个lvalue。基本原因是需要一个lvalue(变量或内存位置)使post-increment执行它的增量。

当你将p_Buf强制转换为uint8_t*类型时,在C中创建了一个rvalue。简单来说,rvalue表示可以传递给函数、赋值给变量等的临时值。Post-increment返回原始值,然后更新存储该值的变量或内存位置,并将其递增。由于它们仅在表达式持续时间内存在,因此无法更新rvalues,post-increment也无法对其进行操作。因此,这就是问题所在。

    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++); 

谢谢您提供的额外解释,这真的很有帮助。问题在于转换的临时性/短暂性(rvalue vs lvalue)。谢谢。 - jaypee

1

在C语言中,对void指针进行递增是一个不好的想法。大多数编译器甚至都不允许编译它。请使用以下方法代替:

p_Buf = (uint8_t*)p_Buf + 1;

0

强制类型转换操作的结果是一个 rvalue,而不是 lvalue。((uint8_t *)p_Buf)++ 不是合法的 C 代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接