2014-10-20 134 views
5

我很困惑,为什么我的编译器在以下条件抛出一个错误:Ç - 表达式必须为可修改的左值

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

不能在虚拟指针增加一次投射?我在这里错过了什么?

+0

不一样,但*非常* [**类似的问题在这里**](http://stackoverflow.com/questions/24002044 /为什么灿I-不-DO-算术上-A-铸造的-A-空指针)。 – WhozCraig 2014-10-20 17:08:36

回答

5

转换操作符:使用此而不是

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的指针。然后当你使用++时,你不会执行任何强制转换(因为它具有正确的类型)并且操作是有效的。

+0

您正将'void'指针转换为'uint8_t'而不是指向它的指针。 – Seprum 2014-10-20 17:06:03

+0

@Seprum不,我不是。你可能看过一个旧的编辑。刷新页面。 – 2501 2014-10-20 17:06:20

+0

已经编辑。 – Seprum 2014-10-20 17:07:29

0

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

1

递增void指针C是个坏主意。大多数编译器甚至不让它被编译。在C

p_Buf = (uint8_t*)p_Buf + 1; 
1

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

当您将p_Buf转换为uint8_t*类型时,您在C中创建了一个右值。简单地说,rvalues表示可以传递给函数,分配给变量等的瞬态值。后增量返回原始值,然后更新存储值的变量或内存位置,并将其递增。因为它们只存在于表达式的持续时间内,所以rvalues不能被更新,并且后增加不能对它们进行操作。因此,与

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

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

在另一方面,当铸分配给一个变量:

p_Buf_8bit = (uint8_t *) p_Buf; 

那么变量p_Buf_8bit左值,它代表一个变量或内存位置。这可以后递增,使这是一个完美的格式良好的陈述在C:

otherFunc (p_Buf_8bit++); 
+0

感谢您的额外解释 - >这真的有帮助。问题是演员的临时/短暂性质(右值vs左值)。谢谢。 – jaypee 2014-10-20 20:17:54

相关问题