为什么+++++ b不起作用?

Bar*_*Das 86 c lvalue

int main ()
{
   int a = 5,b = 2;
   printf("%d",a+++++b);
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码提供以下错误:

错误:需要左值作为递增操作数

但是,如果我把整个空间a++ +++b,然后正常工作.

int main ()
{
   int a = 5,b = 2;
   printf("%d",a++ + ++b);
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

第一个例子中的错误是什么意思?

Lou*_*nco 180

编译器分阶段编写.第一个阶段称为词法分析器,将字符转换为符号结构.所以"++"变成了类似的东西enum SYMBOL_PLUSPLUS.之后,解析器阶段将其转换为抽象语法树,但它无法更改符号.您可以通过插入空格来影响词法分析器(除非它们在引号中,否则为结束符号).

普通词法分析器是贪婪的(有一些例外),所以你的代码被解释为

a++ ++ +b
Run Code Online (Sandbox Code Playgroud)

解析器的输入是符号流,因此您的代码将类似于:

[ SYMBOL_NAME(name = "a"), 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS, 
  SYMBOL_NAME(name = "b") 
]
Run Code Online (Sandbox Code Playgroud)

解析器认为语法不正确.(编辑基于注释:语义不正确,因为你不能将++应用于r值,而++导致这个值)

a+++b 
Run Code Online (Sandbox Code Playgroud)

a++ +b
Run Code Online (Sandbox Code Playgroud)

哪个好.你的其他例子也是如此.

  • +1很好的解释.我必须挑剔:它在语法上是正确的,它只是有一个语义错误(试图增加由'a ++`产生的左值). (27认同)
  • 尼斯.由于贪婪的lexing,许多语言都有类似奇怪的角落案例.这是一个非常奇怪的一个,使表达更长时间使它变得更好:在VBScript中`x = 10&987 && 654 && 321`是非法的,但奇怪的是`x = 10&987 && 654 &&& 321`是合法的. (14认同)
  • 在词法分析器的上下文中,"贪婪"算法通常称为Maximal Munch(http://en.wikipedia.org/wiki/Maximal_munch). (9认同)
  • `a ++`导致rvalue. (7认同)

Pra*_*rav 93

printf("%d",a+++++b);被解释为(a++)++ + b根据最大蒙克规则!.

++(postfix)不评估为a,lvalue但它要求其操作数为lvalue.

!6.4/4表示下一个预处理令牌是可以构成预处理令牌的最长字符序列"


Jer*_*fin 30

词法分析器使用通常称为"最大蒙克"算法来创建令牌.这意味着当它正在读取字符时,它会一直读取字符,直到它遇到的东西不能与它已经拥有的东西相同的一部分(例如,如果它已经读取了数字,那么它具有的是一个数字,如果遇到的话a A,它知道它不能成为数字的一部分.所以它停止并离开A输入缓冲区以用作下一个标记的开头).然后它将该标记返回给解析器.

在这种情况下,这意味着+++++被作为a ++ ++ + b.由于第一个后增量产生一个rvalue,第二个不能应用于它,并且编译器会给出错误.

只是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;
}
Run Code Online (Sandbox Code Playgroud)

使用C++编译器编译和运行(尽管它什么都不做)我很方便(VC++,g ++,Comeau).


Sha*_*our 14

这个确切的例子包含在草案C99标准(C11中的相同细节)第6.4词汇要素第4段中,其中说:

如果输入流已被解析为预处理令牌直到给定字符,则下一个预处理令牌是可构成预处理令牌的最长字符序列.[...]

这也被称为最大蒙克规则,用于词法分析以避免歧义,并通过采用尽可能多的元素来形成有效的令牌.

该段还有两个例子,第二个是你问题的完全匹配,如下:

示例2程序片段x +++++ y被解析为x ++ ++ + y,它违反了增量运算符的约束,即使解析x ++ + ++ y可能产生正确的表达式.

告诉我们:

a+++++b
Run Code Online (Sandbox Code Playgroud)

将被解析为:

a ++ ++ + b
Run Code Online (Sandbox Code Playgroud)

由于第一个后增量的结果是一个rvalue而后增量需要一个左值,因此违反了后增量的约束.这在6.5.2.4 Postfix增量和减量运算符部分中有所说明(强调我的):

后缀增量或减量运算符的操作数应具有限定或不合格的实数或指针类型,并且应为可修改的左值.

postfix ++运算符的结果是操作数的值.

C++ Gotchas一书也涵盖了Gotcha #17 Maximal Munch问题中的这种情况,它在C++中也是同样的问题,它也给出了一些例子.它解释了在处理以下字符集时:

->*
Run Code Online (Sandbox Code Playgroud)

词法分析器可以做以下三件事之一:

  • 把它当作三个令牌:-,>*
  • 把它视为两个令牌:->*
  • 将其视为一个标记: ->*

最大适合规则允许,以避免这些模糊.作者指出它(在C++上下文中):

解决了比它造成的更多问题,但在两种常见情况下,这是一个烦恼.

第一个例子是模板,其模板参数也是模板(在C++ 11中解决),例如:

list<vector<string>> lovos; // error!
                  ^^
Run Code Online (Sandbox Code Playgroud)

将闭括号括号解释为移位运算符,因此需要一个空格来消除歧义:

list< vector<string> > lovos;
                    ^
Run Code Online (Sandbox Code Playgroud)

第二种情况涉及指针的默认参数,例如:

void process( const char *= 0 ); // error!
                         ^^
Run Code Online (Sandbox Code Playgroud)

将被解释为*=赋值运算符,在这种情况下的解决方案是在声明中命名参数.


Pét*_*rök 12

您的编译器拼命尝试解析a+++++b,并将其解释为(a++)++ +b.现在,post-increment(a++)的结果不是左值,即它不能再次递增.

请不要在生产质量计划中编写此类代码.想想那个需要解释你的代码的穷人.


Eri*_*rik 10

(a++)++ +b
Run Code Online (Sandbox Code Playgroud)

a ++返回前一个值,即右值.你不能增加这个.


Red*_*edX 7

因为它会导致未定义的行为.

哪一个?

c = (a++)++ + b
c = (a) + ++(++b)
c = (a++) + (++b)
Run Code Online (Sandbox Code Playgroud)

是的,你和编译器都不知道.

编辑:

真正的原因是其他人说的:

它被解释为(a++)++ + b.

但是后增量需要一个左值(这是一个带名字的变量)但是(a ++)返回一个不能递增的右值,从而导致你得到的错误信息.

向其他人指出这一点.

  • 你可以说同样的a +++ b - (a ++)+ b和a +(++ b)有不同的结果. (5认同)
  • 实际上,postfix ++的优先级高于前缀++,所以`a +++ b`总是`a ++ + b` (4认同)
  • 我不认为这是正确的答案,但我可能是错的.我认为词法分析器将其定义为"a ++ ++ + b",无法解析. (4认同)
  • 我不同意这个答案.'undefined behavior'与标记化歧义完全不同; 而且我认为问题也不是. (2认同)
  • "否则,+++++ b将评估为((a ++)++)+ b"......我现在的观点是`a +++++ b`***评价为`(a ++)++ )+ B`.当然,如果您插入这些括号并重建,则使用GCC,错误消息不会更改. (2认同)

Jim*_*ler 5

我认为编译器认为它是

c =((a ++)++)+ b

++必须具有可修改的值作为操作数.a是可以修改的值.a++但是是'rvalue',它无法修改.

顺便说一句,我在GCC C上看到的错误是相同的,但措辞不同:lvalue required as increment operand.