为什么 a+++++b 不起作用?
int main ()
{
int a = 5,b = 2;
printf("%d",a+++++b);
return 0;
}
此代码给出以下错误:
错误:需要左值作为增量操作数
但是如果我在 a++ +
和 ++b
中放置空格,那么它就可以正常工作。
int main ()
{
int a = 5,b = 2;
printf("%d",a++ + ++b);
return 0;
}
第一个示例中的错误意味着什么?
int main ()
{
int a = 5,b = 2;
printf("%d",a+++++b);
return 0;
}
This code gives the following error:
error: lvalue required as increment operand
But if I put spaces throughout a++ +
and ++b
, then it works fine.
int main ()
{
int a = 5,b = 2;
printf("%d",a++ + ++b);
return 0;
}
What does the error mean in the first example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
编译器是分阶段编写的。第一阶段称为词法分析器,将字符转换为符号结构。因此“++”变成了类似于
枚举SYMBOL_PLUSPLUS
的东西。随后,解析器阶段将其转变为抽象语法树,但它无法更改符号。您可以通过插入空格(结束符号,除非它们在引号中)来影响词法分析器。普通的词法分析器是贪婪的(有一些例外),因此您的代码被解释为
解析器的输入是符号流,因此您的代码将类似于:
解析器认为语法不正确。 (根据评论进行编辑:语义上不正确,因为您不能将 ++ 应用于右值,而 a++ 结果是)
是
哪个可以。你的其他例子也是如此。
Compilers are written in stages. The first stage is called the lexer and turns characters into a symbolic structure. So "++" becomes something like an
enum SYMBOL_PLUSPLUS
. Later, the parser stage turns this into an abstract syntax tree, but it can't change the symbols. You can affect the lexer by inserting spaces (which end symbols unless they are in quotes).Normal lexers are greedy (with some exceptions), so your code is being interpreted as
The input to the parser is a stream of symbols, so your code would be something like:
Which the parser thinks is syntactically incorrect. (EDIT based on comments: Semantically incorrect because you cannot apply ++ to an r-value, which a++ results in)
is
Which is ok. So are your other examples.
printf("%d",a+++++b);
根据最大 Munch 规则被解释为(a++)++ + b
! 。++
(后缀)不会计算为左值
,但它要求其操作数为左值
。<子>!
6.4/4 说
下一个预处理标记是可以构成预处理标记的最长字符序列”
printf("%d",a+++++b);
is interpreted as(a++)++ + b
according to the Maximal Munch Rule!.++
(postfix) doesn't evaluate to anlvalue
but it requires its operand to be anlvalue
.!
6.4/4 says
the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token"
词法分析器使用通常称为“最大咀嚼”的算法来创建标记。这意味着当它读取字符时,它会继续读取字符,直到遇到不能与它已经拥有的令牌相同的东西(例如,如果它正在读取数字,那么它拥有的是一个数字,如果它遇到一个
A
,它知道不能是数字的一部分,因此它会停止并将A
留在输入缓冲区中以用作下一个标记的开头)。 。然后它将该标记返回给解析器。在本例中,这意味着
+++++
被词法分析为a ++ ++ + b
。由于第一个后递增产生一个右值,因此第二个后递增不能应用于它,并且编译器会给出错误。FWIW,在 C++ 中,您可以重载
operator++
来生成左值,这使得它可以工作。例如:使用我手边的 C++ 编译器(VC++、g++、Comeau)进行编译和运行(尽管它什么也不做)。
The lexer uses what's generally called a "maximum munch" algorithm to create tokens. That means as it's reading characters in, it keeps reading characters until it encounters something that can't be part of the same token as what it already has (e.g., if it's been reading digits so what it has is a number, if it encounters an
A
, it knows that can't be part of the number. so it stops and leaves theA
in the input buffer to use as the beginning of the next token). It then returns that token to the parser.In this case, that means
+++++
gets lexed asa ++ ++ + b
. Since the first post-increment yields an rvalue, the second can't be applied to it, and the compiler gives an error.Just FWIW, in C++ you can overload
operator++
to yield an lvalue, which allows this to work. For example:The compiles and runs (though it does nothing) with the C++ compilers I have handy (VC++, g++, Comeau).
C99 标准草案(C11 中的相同详细信息)部分 6.4 词汇元素第 4 段 其中说:
也称为 最大 munch 规则,用于词汇中分析以避免歧义,并通过采用尽可能多的元素来形成有效的令牌。
该段落还有两个示例,第二个示例与您的问题完全匹配,如下所示:
它告诉我们:
将被解析为:
这违反了后增量的约束,因为第一个后增量的结果是右值,而后增量需要左值。
6.5.2.4
后缀递增和递减运算符部分对此进行了介绍(强调我的):和
C++ Gotchas 一书在
Gotcha #17
Maximal Munch Problems 它在 C++ 中也是同样的问题,并且还给出了一些例子。它解释了在处理以下字符集时:词法分析器可以执行以下三件事之一:
-
、>
和*
->
和*
->*
最大咀嚼规则允许它避免这些歧义。作者指出(在 C++ 上下文中):
第一个示例是模板,其模板参数也是模板(已在 C++11 中解决),例如:
它将右尖括号解释为移位运算符 ,因此需要一个空格来消除歧义:
第二种情况涉及指针的默认参数,例如:
会被解释为
*=
赋值运算符,这种情况的解决方案是将参数命名为宣言。This exact example is covered in the draft C99 standard(same details in C11) section 6.4 Lexical elements paragraph 4 which in says:
which is also known as the maximal munch rule which is used in in lexical analysis to avoid ambiguities and works by taking as many elements as it can to form a valid token.
the paragraph also has two examples the second one is an exact match for you question and is as follows:
which tells us that:
will be parsed as:
which violates the constraints on post increment since the result of the first post increment is an rvalue and post increment requires an lvalue. This is covered in section
6.5.2.4
Postfix increment and decrement operators which says (emphasis mine):and
The book C++ Gotchas also covers this case in
Gotcha #17
Maximal Munch Problems it is the same problem in C++ as well and it also gives some examples. It explains that when dealing with the following set of characters:the lexical analyzer can do one of three things:
-
,>
and*
->
and*
->*
The maximal munch rule allows it to avoid these ambiguities. The author points out that it (In the C++ context):
The first example would be templates whose template arguments are also templates (which was solved in C++11), for example:
Which interprets the closing angle brackets as the shift operator, and so a space is required to disambiguate:
The second case involves default arguments for pointers, for example:
would be interpreted as
*=
assignment operator, the solution in this case is to name the parameters in the declaration.您的编译器拼命尝试解析
a+++++b
,并将其解释为(a++)++ +b
。现在,后递增 (a++
) 的结果不是 左值,即不能再次后递增。请永远不要在生产质量程序中编写此类代码。想想那个可怜的家伙正在追随你,他需要解释你的代码。
Your compiler desperately tries to parse
a+++++b
, and interprets it as(a++)++ +b
. Now, the result of the post-increment (a++
) is not an lvalue, i.e. it can't be post-incremented again.Please don't ever write such code in production quality programs. Think about the poor fellow coming after you who needs to interpret your code.
a++ 返回前一个值,即右值。您无法增加此值。
a++ returns the previous value, a rvalue. You can't increment this.
因为它会导致未定义的行为。它是哪一个?
是的,你和编译器都不知道。
编辑:
真正的原因是其他人所说的:
它被解释为
(a++)++ + b
。但后增量需要一个左值(这是一个带有名称的变量),但 (a++) 返回一个无法递增的右值,从而导致您收到错误消息。
感谢其他人指出这一点。
Because it causes undefined behaviour.Which one is it?
Yeah, neither you nor the compiler know it.
EDIT:
The real reason is the one as said by the others:
It gets interpreted as
(a++)++ + b
.but post increment requires a lvalue (which is a variable with a name) but (a++) returns a rvalue which cannot be incremented thus leading to the error message you get.
Thx to the others to pointing this out.
我认为编译器将其视为
c = ((a++)++)+b
++
必须将一个可以修改的值作为操作数。 a 是一个可以修改的值。然而,a++
是一个“右值”,无法修改。顺便说一句,我在 GCC C 上看到的错误是相同的,但措辞不同:
需要左值作为增量操作数
。I think the compiler sees it as
c = ((a++)++)+b
++
has to have as an operand a value that can be modified. a is a value that can be modified.a++
however is an 'rvalue', it cannot be modified.By the way the error I see on GCC C is the same, but differently-worded:
lvalue required as increment operand
.遵循此进动顺序
1.++(预增量)
2.+ -(加法或减法)
3."x"+ "y"将序列
int a = 5,b = 2; 添加
printf("%d",a++ + ++b); //a 是 5,因为它是后增量 b 是 3 前增量
返回0; //是5+3=8
Follow this precesion order
1.++ (pre increment)
2.+ -(addition or subtraction)
3."x"+ "y"add both the sequence
int a = 5,b = 2;
printf("%d",a++ + ++b); //a is 5 since it is post increment b is 3 pre increment
return 0; //it is 5+3=8
C 规范第 6.4 节第 4 段实际上涵盖了这种情况:
Section 6.4 paragraph 4 of the C spec actually covers precisely this case: