Dlaczego a+ + + + + b nie działa?

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

Ten kod daje następujący błąd:

Error: lvalue required as increment operand

Ale jeśli umieszczę spacje w a++ + i ++b, to działa dobrze.

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

Co oznacza błąd w pierwszym przykładzie?

 89
Author: Lundin, 2011-03-17

9 answers

printf("%d",a+++++b); jest interpretowana jako (a++)++ + b zgodnie z maksymalną zasadą Muncha !.

++ (postfix) nie ocenia na lvalue, ale wymaga, aby jego operand był lvalue.

! 6.4 / 4 następny Token wstępnego przetwarzania jest najdłuższą sekwencją znaków, które mogą stanowić token wstępnego przetwarzania"

 98
Author: Prasoon Saurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-13 04:15:14

Kompilatory są pisane etapami. Pierwszy etap nazywa się lekserem i zamienia znaki w strukturę symboliczną. Tak więc " ++ " staje się czymś w rodzaju enum SYMBOL_PLUSPLUS. Później etap parsera przekształca to w abstrakcyjne drzewo składni, ale nie może zmienić symboli. Możesz wpływać na lexer wstawiając spacje (które kończą się symbolami, chyba że są w cudzysłowach).

Zwykłe lexery są chciwe (z pewnymi wyjątkami), więc Twój kod jest interpretowany jako

a++ ++ +b

Wejście do parsera jest strumieniem symboli, więc Twój kod będzie podobny do:

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

Które parser uważa za niepoprawne składniowo. (EDIT based on comments: semantycznie niepoprawne, ponieważ nie można zastosować ++ do wartości r, czego wynikiem jest a++)

a+++b 

Jest

a++ +b

Czyli ok. Podobnie jak inne twoje przykłady.

 181
Author: Lou Franco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-15 14:42:29

Lexer używa tzw. algorytmu "maximum munch" do tworzenia tokenów. Oznacza to, że ponieważ czyta znaki, czyta znaki, dopóki nie napotka czegoś, co nie może być częścią tego samego tokenu, co już ma (np. jeśli czyta cyfry, więc to, co ma, to Liczba, jeśli napotka A, wie, że nie może być częścią liczby. zatrzymuje się więc i pozostawia A w buforze wejściowym do użycia jako początek następnego tokena). Następnie zwraca ten token do parsera.

W tym przypadku oznacza to, że {[3] } jest oznaczana jako a ++ ++ + b. Ponieważ pierwszy post-increment daje wartość R, drugi nie może być zastosowany do niego, a kompilator wyświetla błąd.

Po prostu FWIW, w C++ można przeciążyć operator++, aby uzyskać lvalue, co pozwala to działać. Na przykład:

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

Kompiluje i działa (choć nic nie robi) z kompilatorami C++, które mam handy (VC++, g++, Comeau).

 30
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-15 14:07:16

Ten dokładny przykład jest omówiony w projekcie standardu C99(te same szczegóły w C11) sekcja 6.4 Elementy leksykalne paragraf 4 który w mówi:

Jeśli strumień wejściowy został przetworzony do tokenów wstępnego przetwarzania do podanym znakiem, kolejnym tokenem preprocesora jest najdłuższa Sekwencja znaków, które mogą stanowić token wstępnego przetwarzania. [...]

, która jest również znana jako maksymalna reguła Muncha, która jest używany w analizie leksykalnej, aby uniknąć wieloznaczności i działa, biorąc jak najwięcej elementów, jak to możliwe, aby utworzyć poprawny token.

Akapit ma również dwa przykłady drugi jest dokładnie dopasowany do pytania i jest następujący:

Przykład 2 fragment programu x+++++y jest parsowany jako x ++ ++ + y, który narusza ograniczenie operatorów przyrostowych, mimo że parse x ++ + ++ y może dać poprawne wyrażenie.

Co nam mówi że:

a+++++b

Będzie przetwarzane jako:

a ++ ++ + b

Który narusza ograniczenia przyrostu postu, ponieważ wynikiem pierwszego przyrostu postu jest wartość R, A przyrostu Post wymaga wartości lvalue. Jest to omówione w sekcji 6.5.2.4 operatory Postfix increment i decrement mówiące (podkreślenie):

Operator Postfix increment lub decrement musi mieć kwalifikowany lub niekwalifikowany Typ rzeczywisty lub wskaźnikowy i jest a modyfikowalne lvalue.

I

Wynikiem operatora postfix ++ jest wartość operandu.

Książka C++ Gotchas obejmuje również ten przypadek w Gotcha #17 Maximal Munch Problems jest to ten sam problem w C++, a także podaje kilka przykładów. Wyjaśnia on, że gdy mamy do czynienia z następującym zbiorem znaków:

->*

Analizator leksykalny może wykonać jedną z trzech rzeczy:

  • potraktuj to jako trzy żetony: -, > oraz *
  • traktuj to jako dwa żetony: -> i *
  • traktuj to jako jeden znak: ->*

Reguła maximal munch pozwala uniknąć tych dwuznaczności. Autor zwraca uwagę, że it ( w kontekście C++ ):

Rozwiązuje o wiele więcej problemów niż powoduje, ale w dwóch wspólnych sytuacje, to irytacja.

Pierwszym przykładem będzie szablony, których argumentami szablonów są również szablony (, które rozwiązano w C++11 ), na przykład:

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

Który interpretuje nawiasy kątowe zamknięcia jako operator przesunięcia , a więc do disambiguate potrzebna jest spacja:

list< vector<string> > lovos;
                    ^

Drugi przypadek zawiera domyślne argumenty dla wskaźników, na przykład:

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

Byłoby interpretowane jako *= operator przypisania, rozwiązaniem w tym przypadku jest nazwanie parametrów w deklaracji.

 14
Author: Shafik Yaghmour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-12 06:39:45

Twój kompilator desperacko próbuje parsować a+++++b i interpretuje to jako (a++)++ +b. Wynik post-inkrementacji (a++) nie jest lvalue, tzn. nie można go ponownie zwiększyć po inkrementacji.

Proszę nigdy nie pisać takiego kodu w programach jakości produkcji. Pomyśl o biedaku, który cię ściga, który musi zinterpretować Twój kod.

 12
Author: Péter Török,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-17 15:50:17
(a++)++ +b

A++ zwraca poprzednią wartość, rvalue. Nie możesz tego zwiększyć.

 10
Author: Erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-17 15:33:27

ponieważ powoduje nieokreślone zachowanie.

Który to?
c = (a++)++ + b
c = (a) + ++(++b)
c = (a++) + (++b)
Tak, ani ty, ani kompilator o tym nie wiecie.

EDIT:

Prawdziwym powodem jest ten, jak mówią inni:

Jest interpretowany jako (a++)++ + b.

Ale Post increment wymaga lvalue (która jest zmienną o nazwie), ale (a++) Zwraca wartość R, której nie można zwiększyć, co prowadzi do otrzymanego Komunikatu o błędzie.

Thx dla innych za wskazanie tego Wynocha.

 7
Author: RedX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-15 13:24:45

Myślę, że kompilator widzi to jako

C = ((A++)++) + b

++ musi mieć jako operand wartość, którą można modyfikować. a jest wartością, którą można modyfikować. a++ Jednak jest 'rvalue', nie można go modyfikować.

Swoją drogą błąd jaki widzę na GCC C jest taki sam, ale inaczej sformułowany: lvalue required as increment operand.

 5
Author: Jim Blackler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-15 13:16:18

Wykonaj tę kolejność precesion

1.++ (pre increment)

2.+ - (dodawanie lub odejmowanie)

3."x" + " y " dodaj obie sekwencje

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

 0
Author: rakshit ks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-03 11:49:47