1. 问题
有人问:int a=5; 为什么++a=1能编译通过a++=1编译错误呢?
解释:不管是++a=1还是a++=1在C编译环境下都无法编译通过,但在C++中,++a=1可以编译通过,而a++=1无法编译通过,这也是C和C++的一个不同。因此,这是一个关于C++的问题。
2. 分析
不管是C还是C++,语句a++=1;的行为是未定义的,因为它违反了“如果在没有序列点的表达式中多次修改同一标量的行为是未定义行为”。
对于++a=1,等效于(a+=1)=1,对于C而已?(a+=1)不是左值,因此不能将1赋值给++a。因此,在C中编译通不过,给出的错误信息是:
[Error] lvalue required as left operand of assignment
但对于C++而言,表达式++a=1是正确的,因为++a在C++ 标准中是左值,因此,语句++a=1;在C++中是正确的语句。虽然该语句在C++中是正确,但不建议这样写。
表达式a++=1在C或C++中都是错误的,因为它试图两次修改同一个对象,这是不允许的。讨论这个话题就像讨论一个错误的时钟在一个小时后的时间是多少而已。
注:左值(Ivalue)这个词最初源自赋值表达式E1=E2,其中左操作数E1必须是(可修改的)表达式。对象(object)是一块内存区域,可以读取它的值或者向它存储数据。一般将左值视为对象的“定位值(locator value)”,即左值是一种表达式,可以通过它读取或修改它所引用的对象。例如,表达式a和b都是左值,但表达式3和b+3都不是左值。再如,若一元表达式E是一个指向对象的指针,则*E是一个左值,表示E指向的对象。
C99对左值的定义是:左值是具有对象类型或非void的不完整类型的表达式,如果左值在求值时没有指定对象,则其行为是未定义的。
C11起对左值的定义是:左值是一个表达式,该表达式潜在地指示一个对象,且该对象类型不是void,如果左值在求值时没有指定对象,则其行为是未定义的。
3. 进一步分析
在C标准中,由自增和自减运算符构成的表达式是右值(在C标准中,有时把右值(rvalue)描述为表达式的值),但在C++中,前缀形式的运算符构成的表达式是左值。因此,在C语言中,即a++和++a不是左值而是右值,因此无法为它们赋值。而在C++ 中++a是左值,因此可以给++a赋值,这就是为什么在C++中语句++a=1;?能编译通过的原因。
注:在C标准中,赋值和复合赋值运算符构成的表达式是右值,但在C++中是左值。例如?表达式(a=3*4)=5+6在C中是错误的,但在C++ 中是正确的。对于表达式a=3*4来说,在C中不是左值,因此不能将表达式5+6赋值给它,但在C++ 中它是左值,因此,可以将5+6赋值给(a=3*4)。
4. 经验
如果一个变量出现在一个函数的多个参数中,不要对该变量使用递增或递减运算符。
如果一个变量多次出现在一个表达式中,不要对该变量使用递增或递减运算符。
C语言学习50
C语言学习 · 目录
上一篇C 语言基本概念----序列点下一篇C语言辨析——深入理解格式字符的用法