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;
}
此代码给出以下错误:
错误:需要左值作为增量操作数
但是,如果我在a++ +
和之间放置空格++b
,则效果很好。
int main ()
{
int a = 5,b = 2;
printf("%d",a++ + ++b);
return 0;
}
该错误在第一个示例中意味着什么?
x+++++y
被解析为x ++ ++ + y
,这违反了对增量运算符的约束,即使该解析x ++ + ++ y
可能产生正确的表达式也是如此。”
Answers:
编译器是分阶段编写的。第一阶段称为词法分析器,它将字符转换为符号结构。所以“ ++”变成了类似enum SYMBOL_PLUSPLUS
。稍后,解析器阶段将其转变为抽象语法树,但是它无法更改符号。您可以通过插入空格(除非符号用引号引起来,否则空格)来影响词法分析器。
普通词法编辑器是贪婪的(有一些例外),因此您的代码被解释为
a++ ++ +b
解析器的输入是符号流,因此您的代码将类似于:
[ SYMBOL_NAME(name = "a"),
SYMBOL_PLUS_PLUS,
SYMBOL_PLUS_PLUS,
SYMBOL_PLUS,
SYMBOL_NAME(name = "b")
]
解析器认为在语法上是不正确的。(根据注释进行编辑:从语义上讲是不正确的,因为您不能将++应用于a值导致的r值)
a+++b
是
a++ +b
没关系 您的其他示例也是如此。
a++
导致右值。
x = 10&987&&654&&321
是非法的,但奇怪的x = 10&987&&654&&&321
是合法的。
词法分析器使用通常称为“最大数量”的算法来创建令牌。这意味着在读取字符时,它将一直读取字符,直到遇到无法与已有标记相同的标记(例如,如果一直在读取数字,那么它就是一个数字,如果遇到了) an A
,它知道不能是数字的一部分,所以它停止并离开A
在输入缓冲区中,以用作下一个标记的开头)。然后,它将令牌返回给解析器。
在这种情况下,这意味着+++++
将词法化为a ++ ++ + b
。由于第一个后增量产生一个右值,因此第二个后增量不能应用于它,并且编译器会给出错误。
只是FWIW,在C ++中,您可以重载operator++
以产生一个左值,这使它可以工作。例如:
struct bad_code {
bad_code &operator++(int) {
return *this;
}
int operator+(bad_code const &other) {
return 1;
}
};
int main() {
bad_code a, b;
int c = a+++++b;
return 0;
}
使用方便的C ++编译器(VC ++,g ++,Comeau)进行编译和运行(尽管不执行任何操作)。
16FA
是一个完全正常的十六进制数包含一个A.
0x
在开始时不带a ,它仍然将16
其后跟FA
,而不是一个十六进制数。
0x
不是数字的一部分。
x
数字,这似乎完全没有必要。
这个确切的例子在C99标准草案(C11中的相同细节)第6.4节Lexical elements第4段中有所说明,其中说:
如果已将输入流解析为最多给定字符的预处理令牌,则下一个预处理令牌是可以构成预处理令牌的最长字符序列。[...]
它也被称为最大割礼规则,在词法分析中用于避免歧义,并且通过采用尽可能多的元素来形成有效标记而起作用。
该段还有两个示例,第二个示例完全符合您的问题,如下所示:
示例2:程序片段x +++++ y被解析为x +++++ y,即使解析x ++++ y可能产生正确的表达式,也违反了对增量运算符的约束。
告诉我们:
a+++++b
将被解析为:
a ++ ++ + b
这违反了对职位增量的限制,因为第一个职位增量的结果是一个右值,而职位增量需要一个左值。这在6.5.2.4
Postfix增量和减量运算符部分中进行了介绍,其中(强调):
后缀递增或递减运算符的操作数应具有合格或不合格的实数或指针类型,并且应为可修改的左值。
和
后缀++运算符的结果是操作数的值。
《C ++ Gotchas》一书在“ Gotcha #17
最大蒙克问题”中也涉及了这种情况,在C ++中也是同样的问题,并给出了一些示例。它说明了在处理以下字符集时的问题:
->*
词法分析器可以执行以下三种操作之一:
-
,>
和*
->
和*
->*
在最大适合规则允许,以避免这些模糊。作者指出了这一点(在C ++上下文中):
解决的问题多于其所能解决的问题,但是在两种常见情况下,这很烦人。
第一个示例是模板,模板的模板参数也是模板(在C ++ 11中已解决),例如:
list<vector<string>> lovos; // error!
^^
它将右尖括号解释为shift运算符,因此需要一个空格来消除歧义:
list< vector<string> > lovos;
^
第二种情况涉及指针的默认参数,例如:
void process( const char *= 0 ); // error!
^^
将被解释为*=
赋值运算符,这种情况下的解决方案是在声明中命名参数。
>>
规则是在问:stackoverflow.com/questions/15785496/...
因为它会导致不确定的行为。
哪一个?
c = (a++)++ + b
c = (a) + ++(++b)
c = (a++) + (++b)
是的,您和编译器都不知道。
编辑:
真正的原因是其他人所说的:
它被解释为(a++)++ + b
。
但是后递增需要一个左值(这是一个带名称的变量),但是(a ++)返回一个右值,该右值不能递增,从而导致出现错误消息。
谢谢其他人指出这一点。
a+++b
始终如此a++ + b
a++ ++ +b
无法解析的。
a+++++b
确实是评估为(a++)++)+b
。当然,对于GCC,如果您插入这些括号并进行重建,则错误消息不会更改。
遵循此先行顺序
1。++(预递增)
2. +-(加法或减法)
3.“ x” +“ y”将两个序列相加
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