Po zbadaniu przeczytałem, że operator inkrementacji wymaga, aby operand miał modyfikowalny obiekt danych: https://en.wikipedia.org/wiki/Increment_and_decrement_operators .
Z tego sądzę, że daje błąd kompilacji, ponieważ (a+b)
jest to tymczasowa liczba całkowita, więc nie można jej modyfikować.
Czy to rozumienie jest prawidłowe? To był mój pierwszy raz, kiedy próbowałem zbadać problem, więc jeśli było coś, czego powinienem był szukać, proszę o poradę.
c = a + b + 1
twój zamiar jest jaśniejszy, a także krótszy do wpisania. Operatory inkrementacji / dekrementacji robią dwie rzeczy: 1. one i ich argument tworzą wyrażenie (którego można użyć np. W pętli for), 2. modyfikują argument. W swoim przykładzie używasz właściwości 1, ale nie właściwości 2, ponieważ odrzucasz zmodyfikowany argument. Jeśli nie potrzebujesz właściwości 2. i potrzebujesz tylko wyrażenia, możesz po prostu napisać wyrażenie, np. X + 1 zamiast x ++.Odpowiedzi:
To tylko reguła, to wszystko i prawdopodobnie istnieje po to, aby (1) ułatwić pisanie kompilatorów C i (2) nikt nie przekonał komitetu normalizacyjnego C do złagodzenia tego problemu.
Mówiąc nieformalnie, możesz pisać tylko
++foo
wtedy, gdyfoo
może pojawić się po lewej stronie wyrażenia przypisania, takiego jakfoo = bar
. Ponieważ nie możesz pisaća + b = bar
, nie możesz też pisać++(a + b)
.Nie ma prawdziwego powodu, dla
a + b
którego nie można by uzyskać tymczasowego, na którym++
można by operować, a wynikiem tego jest wartość wyrażenia++(a + b)
.źródło
++
czasami miał efekt uboczny modyfikacji czegoś, a czasami po prostu nie.Standard C11 stwierdza w sekcji 6.5.3.1
A „modyfikowalna lwartość” jest opisana w sekcji 6.3.2.1, podrozdziale 1
Więc
(a+b)
nie jest modyfikowalną lwartością i dlatego nie kwalifikuje się do operatora zwiększania przedrostka.źródło
Masz rację.
++
próbuje przypisać nową wartość do zmiennej pierwotnej. Więc++a
weźmie wartośća
, doda1
do niej, a następnie przypisze z powrotem doa
. Ponieważ, jak powiedziałeś, (a + b) jest wartością tymczasową, a nie zmienną z przypisanym adresem pamięci, przypisanie nie może zostać wykonane.źródło
Myślę, że głównie odpowiedziałeś na własne pytanie. Mogę dokonać niewielkiej zmiany w Twoim frazie i zastąpić „zmienną tymczasową” „wartością r”, jak wspomniał C.Gibbons.
Terminy zmienna, argument, zmienna tymczasowa i tak dalej staną się bardziej zrozumiałe, gdy dowiesz się o modelu pamięci C (wygląda to na ładne omówienie: https://www.geeksforgeeks.org/memory-layout-of-c-program/ ).
Termin „wartość r” może wydawać się nieprzejrzysty, kiedy dopiero zaczynasz, więc mam nadzieję, że poniższe wskazówki pomogą rozwinąć intuicję na jego temat.
Lwartość / rwartość mówią o różnych stronach znaku równości (operator przypisania): lwartość = lewa strona (mała litera L, a nie „jedynka”) rwartość = prawa strona
Dowiedz się trochę o tym, jak C używa pamięci (i rejestrów), aby zrozumieć, dlaczego rozróżnienie jest ważne. W szerokich pociągnięciach pędzla kompilator tworzy listę instrukcji języka maszynowego, które obliczają wynik wyrażenia (wartość r), a następnie umieszcza ten wynik gdzieś (lwartość). Wyobraź sobie kompilator obsługujący następujący fragment kodu:
W pseudokodzie asemblera może to wyglądać podobnie do tego przykładu zabawki:
Operator ++ (i jego odpowiednik) potrzebują „gdzieś” do zmodyfikowania, w zasadzie wszystkiego, co może działać jako lwartość.
Zrozumienie modelu pamięci C będzie pomocne, ponieważ uzyskasz lepsze wyobrażenie o tym, jak argumenty są przekazywane do funkcji i (ostatecznie) jak pracować z dynamiczną alokacją pamięci, taką jak funkcja malloc (). Z podobnych powodów możesz w pewnym momencie przestudiować proste programowanie w asemblerze, aby uzyskać lepsze pojęcie o tym, co robi kompilator. Również jeśli używasz gcc , opcja -S "Zatrzymaj po etapie właściwej kompilacji; nie asembluj". może być interesujący (choć polecam wypróbowanie go na małym fragmencie kodu).
Na marginesie: instrukcja ++ istnieje od 1969 roku (chociaż zaczęła się w poprzedniku C, B):
Po tym odnośniku wikipedii przejdziesz do interesującego artykułu Dennisa Ritchiego („R” w „K&R C”) na temat historii języka C, z linkiem tutaj dla wygody: http://www.bell-labs.com/ usr / dmr / www / chist.html, gdzie możesz wyszukać „++”.
źródło
Powodem jest to, że standard wymaga, aby operand był lwartością. Wyrażenie
(a+b)
nie jest lwartością, więc stosowanie operatora przyrostu jest niedozwolone.Teraz można by powiedzieć: „OK, to rzeczywiście powód, ale tak naprawdę nie ma innego * prawdziwego * powodu niż ten” , ale niestety konkretne sformułowanie tego, jak operator faktycznie działa, wymaga, aby tak było.
Oczywiście nie możesz pisać,
E += 1
jeśliE
nie jest lwartością. Szkoda, bo równie dobrze można było powiedzieć: „zwiększa E o jeden” i gotowe. W takim przypadku zastosowanie operatora na wartości innej niż l byłoby (w zasadzie) całkowicie możliwe, kosztem nieco bardziej złożonego kompilatora.Definicja mogłaby zostać w trywialny sposób przeformułowana (myślę, że nie jest to nawet pierwotnie C, ale dziedzictwo B), ale zrobienie tego zasadniczo zmieniłoby język na coś, co nie jest już zgodne z jego poprzednimi wersjami. Ponieważ możliwa korzyść jest raczej niewielka, ale możliwe konsekwencje są ogromne, to się nigdy nie wydarzyło i prawdopodobnie nigdy się nie wydarzy.
Jeśli weźmiesz pod uwagę C ++ oprócz C (pytanie jest oznaczone tagiem C, ale była dyskusja na temat przeciążenia operatorów), historia staje się jeszcze bardziej skomplikowana. W C trudno sobie wyobrazić, że tak może być, ale w C ++ rezultatem
(a+b)
może być coś, czego w ogóle nie można zwiększyć, lub inkrementacja może mieć bardzo znaczące skutki uboczne (nie tylko dodanie 1). Kompilator musi być w stanie sobie z tym poradzić i zdiagnozować problematyczne przypadki, gdy się pojawią. W przypadku lwartości sprawdzenie tego jest trochę trywialne. Inaczej jest w przypadku jakiegokolwiek przypadkowego wyrażenia w nawiasach, które rzucasz na biedaka.To nie jest prawdziwy powód, dla którego nie mógł być zrobione, ale z pewnością jest to wyjaśnienie, dlaczego ludzie, którzy to wdrożyli, nie są do końca zachwyceni, dodając taką cechę, która obiecuje bardzo niewielkie korzyści bardzo niewielu ludziom.
źródło
(a + b) zwraca wartość r, której nie można zwiększać.
źródło
++ próbuje nadać wartość oryginalnej zmiennej, a ponieważ (a + b) jest wartością tymczasową, nie może wykonać operacji. I są to w zasadzie zasady konwencji programowania C, które ułatwiają programowanie. Otóż to.
źródło
Gdy wykonywane jest wyrażenie ++ (a + b), to na przykład:
źródło