我很困惑为什么我的编译器在以下情况下抛出错误:
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++);
}
}
一旦施放,空指针是否会递增?我错过了一些基本的东西吗?
答案 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代码。