programing tip

a +++++ b가 작동하지 않는 이유는 무엇입니까?

itbloger 2020. 9. 15. 07:28
반응형

a +++++ b가 작동하지 않는 이유는 무엇입니까?


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

이 코드는 다음 오류를 제공합니다.

오류 : 증가 피연산자로 lvalue 필요

하지만 전반에 걸쳐 공간을 세우면 a++ +하고 ++b다음 잘 작동합니다.

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

첫 번째 예에서 오류는 무엇을 의미합니까?


printf("%d",a+++++b);(a++)++ + bMaximal Munch Rule에 따라 해석됩니다 ! .

++(접미사)는로 평가되지 않지만 lvalue피연산자가 lvalue.

! 6.4 / 4는 다음 전처리 토큰이 전처리 토큰을 구성 할 수있는 가장 긴 문자 시퀀스라고 말합니다. "


컴파일러는 단계적으로 작성됩니다. 첫 번째 단계는 렉서 (lexer)라고하며 문자를 기호 구조로 바꿉니다. 그래서 "++"는 enum SYMBOL_PLUSPLUS. 나중에 파서 단계는 이것을 추상 구문 트리로 바꾸지 만 기호를 변경할 수는 없습니다. 공백을 삽입하여 어휘 분석기에 영향을 줄 수 있습니다 (따옴표로 묶이지 않는 한 기호를 끝냄).

일반 어휘 분석기는 탐욕 스럽기 때문에 (일부 예외가 있음) 코드는 다음과 같이 해석됩니다.

a++ ++ +b

파서에 대한 입력은 심볼 스트림이므로 코드는 다음과 같습니다.

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

구문 분석기가 구문 상 잘못되었다고 생각하는 것. (주석을 기반으로 편집 : ++를 r- 값에 적용 할 수 없기 때문에 의미 상 잘못됨, a ++ 결과)

a+++b 

이다

a++ +b

괜찮습니다. 다른 예도 마찬가지입니다.


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


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.


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++)++ +b

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


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.


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.

참고URL : https://stackoverflow.com/questions/5341202/why-doesnt-ab-work

반응형