[c] 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

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


답변

어휘 분석기는 일반적으로 “maximum munch”알고리즘을 사용하여 토큰을 만듭니다. 즉, 문자를 읽을 때 이미 가지고있는 것과 동일한 토큰의 일부가 될 수없는 무언가를 만날 때까지 계속 문자를 읽습니다 (예 : 숫자를 읽었으므로 숫자가있는 경우, an A, 그것은 숫자의 일부가 될 수 없다는 것을 알고 있습니다. 그래서 그것은 멈추고 A다음 토큰의 시작으로 사용하기 위해 입력 버퍼에 남겨 둡니다 ). 그런 다음 해당 토큰을 파서에 반환합니다.

이 경우, 그 수단 +++++으로 lexed됩니다 a ++ ++ + b. 첫 번째 사후 증가는 rvalue를 산출하므로 두 번째는 적용 할 수 없으며 컴파일러는 오류를 제공합니다.

FWIW 만 있으면 C ++에서 오버로드 operator++하여 lvalue를 생성 할 수 있습니다 . 예를 들면 :

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)를 사용하여 컴파일하고 실행합니다 (아무것도하지 않음).


답변

이 정확한 예는 C99 표준 초안 ( C11의 세부 사항과 동일 ) 섹션 6.4 어휘 요소 단락 4 에서 다룹니다 .

입력 스트림이 주어진 문자까지 사전 처리 토큰으로 구문 분석 된 경우 다음 사전 처리 토큰은 사전 처리 토큰을 구성 할 수있는 가장 긴 문자 시퀀스입니다. […]

모호함을 피하기 위해 어휘 분석에 사용되는 최대 뭉크 규칙 으로도 알려져 있으며 유효한 토큰을 형성하기 위해 가능한 한 많은 요소를 취하여 작동합니다.

단락에는 또한 두 번째 예가 질문에 정확히 일치하며 다음과 같은 두 가지 예가 있습니다.

예 2 프로그램 조각 x +++++ y는 x ++ ++ + y로 구문 분석되며, 이는 x ++ + ++ y 구문 분석이 올바른 식을 생성 할 수 있지만 증가 연산자에 대한 제약 조건을 위반합니다.

이는 우리에게 다음을 알려줍니다.

a+++++b

다음과 같이 구문 분석됩니다.

a ++ ++ + b

첫 번째 포스트 증분의 결과는 rvalue이고 포스트 증분에는 lvalue가 필요하기 때문에 포스트 증분에 대한 제약 조건을 위반합니다. 이 절에서 다루고있다 6.5.2.4 후위 증가 및 감소 연산자 (라고 강조 광산 ) :

접미사 증가 또는 감소 연산자의 피연산자는 규정 된 또는 규정되지 않은 실수 또는 포인터 유형을 가져야 하며 수정 가능한 lvalue 여야합니다.

접미사 ++ 연산자의 결과는 피연산자의 값입니다.

이 책은 C ++ 둘점은 또한이 경우 커버 Gotcha #17 최대한 뭉크 문제 는 동일한 문제가 C ++ 뿐만 아니라 그것은 또한 몇 가지 예를 제공합니다. 다음 문자 집합을 처리 할 때 설명합니다.

->*

어휘 분석기는 다음 세 가지 중 하나를 수행 할 수 있습니다.

  • 세 개의 토큰으로 취급 : -, >*
  • 이 토큰로 취급 : ->*
  • 하나의 토큰으로 취급하십시오. ->*

최대 뭉크의 규칙은 이러한 모호성을 피할 수 있습니다. 저자는 다음과 같이 지적합니다 ( C ++ 컨텍스트에서 ) :

원인보다 더 많은 문제를 해결하지만, 두 가지 일반적인 상황에서는 성가신 일입니다.

첫 번째 예는 템플릿 인수도 템플릿 ( C ++ 11에서 해결됨) 인 템플릿 입니다. 예를 들면 다음과 같습니다.

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

닫는 꺾쇠 괄호를 시프트 연산자 로 해석 하므로 명확성을 위해 공백이 필요합니다.

list< vector<string> > lovos;
                    ^

두 번째 경우에는 포인터에 대한 기본 인수가 포함됩니다. 예를 들면 다음과 같습니다.

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

*=할당 연산자 로 해석됩니다 .이 경우 해결책은 선언에서 매개 변수의 이름을 지정하는 것입니다.


답변

당신의 컴파일러는 필사적으로 파싱을 시도하고 a+++++b그것을 (a++)++ +b. 이제 post-increment ( a++) 의 결과 는 lvalue 가 아닙니다. 즉, 다시 post-increment 할 수 없습니다.

프로덕션 품질 프로그램에서 이러한 코드를 작성하지 마십시오. 당신의 코드를 해석해야하는 가난한 사람이 당신을 쫓는 것에 대해 생각해보십시오.


답변

(a++)++ +b

a ++는 이전 값인 rvalue를 반환합니다. 이것을 증가시킬 수 없습니다.


답변

정의되지 않은 동작을 유발하기 때문입니다.

어떤거야?

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

예, 당신도 컴파일러도 그것을 모릅니다.

편집하다:

진짜 이유는 다른 사람들이 말한 것입니다.

로 해석됩니다 (a++)++ + b.

그러나 post increment에는 lvalue (이름이있는 변수)가 필요하지만 (a ++)는 증가 할 수없는 rvalue를 반환하므로 오류 메시지가 표시됩니다.

이것을 지적하는 다른 사람들에게 Thx.