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

发布于 2024-10-23 15:04:30 字数 366 浏览 4 评论 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;
}

第一个示例中的错误意味着什么?

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

孤城病女 2024-10-30 15:04:30

编译器是分阶段编写的。第一阶段称为词法分析器,将字符转换为符号结构。因此“++”变成了类似于枚举SYMBOL_PLUSPLUS的东西。随后,解析器阶段将其转变为抽象语法树,但它无法更改符号。您可以通过插入空格(结束符号,除非它们在引号中)来影响词法分析器。

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

a++ ++ +b

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

[ SYMBOL_NAME(name = "a"), 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS, 
  SYMBOL_NAME(name = "b") 
]

解析器认为语法不正确。 (根据评论进行编辑:语义上不正确,因为您不能将 ++ 应用于右值,而 a++ 会导致该值)

a+++b 

a++ +b

哪个可以。你的其他例子也是如此。

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

a++ ++ +b

The input to the parser is a stream of symbols, so your code would be something like:

[ SYMBOL_NAME(name = "a"), 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS, 
  SYMBOL_NAME(name = "b") 
]

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)

a+++b 

is

a++ +b

Which is ok. So are your other examples.

安稳善良 2024-10-30 15:04:30

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 an lvalue but it requires its operand to be an lvalue.

!
6.4/4 says
the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token"

月竹挽风 2024-10-30 15:04:30

词法分析器使用通常称为“最大咀嚼”的算法来创建标记。这意味着当它读取字符时,它会继续读取字符,直到遇到不能与它已经拥有的令牌相同的东西(例如,如果它正在读取数字,那么它拥有的是一个数字,如果它遇到一个 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)进行编译和运行(尽管它什么也不做)。

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 the A 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 as a ++ ++ + 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:

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;
}

The compiles and runs (though it does nothing) with the C++ compilers I have handy (VC++, g++, Comeau).

往昔成烟 2024-10-30 15:04:30

C99 标准草案(C11 中的相同详细信息)部分 6.4 词汇元素第 4 段 其中说:

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

也称为 最大 munch 规则,用于词汇中分析以避免歧义,并通过采用尽可能多的元素来形成有效的令牌。

该段落还有两个示例,第二个示例与您的问题完全匹配,如下所示:

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

它告诉我们:

a+++++b

将被解析为:

a ++ ++ + b

这违反了后增量的约束,因为第一个后增量的结果是右值,而后增量需要左值。 6.5.2.4 后缀递增和递减运算符部分对此进行了介绍(强调我的):

后缀自增或自减运算符的操作数应具有
合格或不合格的实数或指针类型,应为
可修改的左值。

后缀++运算符的结果是操作数的值。

C++ Gotchas 一书在 Gotcha #17 Maximal Munch Problems 它在 C++ 中也是同样的问题,并且还给出了一些例子。它解释了在处理以下字符集时:

->*

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

  • 将其视为三个标记:->*
  • 将其视为两个标记:->*
  • 将其视为一个标记:->*

最大咀嚼规则允许它避免这些歧义。作者指出(在 C++ 上下文中):

解决的问题比它引起的问题多得多,但有两个常见问题
情况,这是一个烦恼。

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

list<vector<string>> lovos; // error!
                  ^^

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

list< vector<string> > lovos;
                    ^

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

void process( const char *= 0 ); // error!
                         ^^

会被解释为*=赋值运算符,这种情况的解决方案是将参数命名为宣言。

This exact example is covered in the draft C99 standard(same details in C11) section 6.4 Lexical elements paragraph 4 which in says:

If the input stream has been parsed into preprocessing tokens up to a
given character, the next preprocessing token is the longest sequence
of characters that could constitute a preprocessing token. [...]

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:

EXAMPLE 2 The program fragment x+++++y is parsed as x ++ ++ + y, which
violates a constraint on increment operators, even though the parse x
++ + ++ y might yield a correct expression.

which tells us that:

a+++++b

will be parsed as:

a ++ ++ + b

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):

The operand of the postfix increment or decrement operator shall have
qualified or unqualified real or pointer type and shall be a
modifiable lvalue.

and

The result of the postfix ++ operator is the value of the operand.

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:

  • Treat it as three tokens: -, > and *
  • Treat it as two tokens: -> and *
  • Treat it as one token: ->*

The maximal munch rule allows it to avoid these ambiguities. The author points out that it (In the C++ context):

solves many more problems than it causes, but in two common
situations, it’s an annoyance.

The first example would be templates whose template arguments are also templates (which was solved in C++11), for example:

list<vector<string>> lovos; // error!
                  ^^

Which interprets the closing angle brackets as the shift operator, and so a space is required to disambiguate:

list< vector<string> > lovos;
                    ^

The second case involves default arguments for pointers, for example:

void process( const char *= 0 ); // error!
                         ^^

would be interpreted as *= assignment operator, the solution in this case is to name the parameters in the declaration.

书信已泛黄 2024-10-30 15:04:30

您的编译器拼命尝试解析 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.

宁愿没拥抱 2024-10-30 15:04:30
(a++)++ +b

a++ 返回前一个值,即右值。您无法增加此值。

(a++)++ +b

a++ returns the previous value, a rvalue. You can't increment this.

分分钟 2024-10-30 15:04:30

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

它是哪一个?

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

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

编辑:

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

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

但后增量需要一个左值(这是一个带有名称的变量),但 (a++) 返回一个无法递增的右值,从而导致您收到错误消息。

感谢其他人指出这一点。

Because it causes undefined behaviour.

Which one is it?

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

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.

浮生未歇 2024-10-30 15:04:30

我认为编译器将其视为

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.

柠檬 2024-10-30 15:04:30

遵循此进动顺序

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

情独悲 2024-10-30 15:04:30

C 规范第 6.4 节第 4 段实际上涵盖了这种情况:

如果输入流已被解析为预处理标记,直到给定字符,则下一个
预处理标记是可以构成预处理的最长字符序列
令牌。此规则有一个例外:仅识别标头名称预处理标记
在 #include 预处理指令内和 #pragma 内实现定义的位置中
指令。在这种情况下,字符序列可以是标头名称或字符串
字面意思被认为是前者。

示例 1 程序片段 1Ex 被解析为预处理数字标记(不是有效的浮点数或整数)
常量标记),即使解析为一对预处理标记 1 和 Ex 可能会生成有效的表达式(例如
例如,如果 Ex 是定义为 +1 的宏)。类似地,程序片段1E1被解析为预处理号(一
这是一个有效的浮点常量标记),无论 E 是否是宏名称。

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

Section 6.4 paragraph 4 of the C spec actually covers precisely this case:

If the input stream has been parsed into preprocessing tokens up to a given character, the next
preprocessing token is the longest sequence of characters that could constitute a preprocessing
token. There is one exception to this rule: header name preprocessing tokens are recognized only
within #include preprocessing directives and in implementation-defined locations within #pragma
directives. In such contexts, a sequence of characters that could be either a header name or a string
literal is recognized as the former.

EXAMPLE 1 The program fragment 1Ex is parsed as a preprocessing number token (one that is not a valid floating or integer
constant token), even though a parse as the pair of preprocessing tokens 1 and Ex might produce a valid expression (for
example, if Ex were a macro defined as +1 ). Similarly, the program fragment 1E1 is parsed as a preprocessing number (one
that is a valid floating constant token), whether or not E is a macro name.

EXAMPLE 2 The program fragment x+++++y is parsed as x ++ ++ + y , which violates a constraint on increment operators,
even though the parse x ++ + ++ y might yield a correct expression

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文