Przypadkowa obserwacja wydaje się, że na StackOverflow.com pojawiają się pytania, czy „++ i == i ++”. To pytanie jest ciągle zadawane, myślę, że widziałem je 6 lub 7 razy w ciągu ostatnich 2 miesięcy.
Zastanawiam się tylko, dlaczego programiści C są tak zainteresowani? Ta sama koncepcja / pytanie istnieje również dla programistów C # i Java, ale myślę, że widziałem tylko jedno pytanie związane z C #.
Czy to dlatego, że tak wiele przykładów używa ++ i? Czy dlatego, że istnieje popularna książka lub samouczek? Czy to dlatego, że programiści C po prostu uwielbiają wcisnąć jak najwięcej w jedną linię dla „wydajności” / „wydajności”, a zatem częściej spotykają się z „dziwnymi” konstrukcjami używającymi operatora ++?
c
undefined-behavior
Michael Stum
źródło
źródło
++i == i++
, czy bardziej ogólnie różnicę w znaczeniu między++i
ii++
?Odpowiedzi:
Podejrzewam, że przynajmniej część tego jest nieco prostsza: nawet teraz na początku roku szkolnego widzimy wiele takich pytań, które stopniowo się zmniejszają przez cały rok.
W związku z tym uważam, że można zgadywać, że sporo z nich jest po prostu wynikiem zajęć, w których nauczyciel mówi co najmniej o tym, ale nie wyjaśnia zbyt dobrze swoich argumentów (tak często, jak nie bo on tak naprawdę ich nie rozumie). Zwłaszcza w oparciu o osoby, które wydają się zadawać te pytania, niewiele opiera się na faktycznym kodowaniu.
źródło
Ponieważ programiści C MUSZĄ zrozumieć kolejność operacji. Programiści C # niekoniecznie używają operatorów bitowych (&, |, ~) lub operatorów prefiksów, ponieważ zwykle bardziej martwimy się o inne rzeczy. Jednak my, deweloperzy C #, nie zdajemy sobie sprawy, że powinniśmy wiedzieć, co robią operatorzy, z których korzystamy na co dzień i jak z nich właściwie korzystać. Większość z nas po prostu omija miejsca, w których może to stanowić problem.
Jaki jest wynik tego fragmentu?
Powiedziałbym, że spora liczba doświadczonych deweloperów C # nie ma pojęcia, jaki jest wynik działania konsoli.
źródło
if (myList[i++] == item)
. Sprytny. Znalazłem to, szukając źródła wyjątku IndexOutOfRange ... Rzeczywiście, bardzo „sprytne”.++
używany na float i muszę powiedzieć, że nie wydaje się to zbyt odpowiednie. Czy ludzie to robią? (Wolałbym+= 1
)Myślę, że to oczywiste. W języku C #, dla
int i
,i++ == ++i
jest zawsze fałszywe natomiast++i == i++
jest zawsze prawdziwe, niezawodnie, a każdy, kto jest zainteresowany może dowiedzieć się łatwo po prostu poprzez uczenie zasad C # (lub nawet po prostu uruchomienie go).Z drugiej strony w C i C ++ jest prawie niezdefiniowany, ponieważ zależy to od kompilatora, środowiska wykonawczego, platformy itp., Więc odpowiedź na pytanie jest trudniejsza, więc wiele osób go zadaje.
źródło
To popularne pytanie, ponieważ jest to podchwytliwe pytanie. Nie jest zdefiniowane .
Powyższy link prowadzi do FAQ na stronie głównej Bjarnesa Stroustrupa, który szczegółowo zajmuje się tym pytaniem i wyjaśnia, dlaczego ta konstrukcja jest niezdefiniowana. Mówi to:
źródło
Najprawdopodobniej dlatego, że w C naprawdę ma to znaczenie, jeśli piszesz
i++
lub++i
robisz arytmetykę wskaźników. Tami
kluczowe znaczenie może mieć zwiększenie przed operacją lub po niej. Dam ci przykład, ale ostatni raz napisałem C 10 lat temu ...W języku C # nigdy nie spotkałem się z sytuacją, która wymagałaby ode mnie myślenia
i++
lub++i
ponieważ AFAIK, dla pętli for / while, to naprawdę nie ma znaczenia.źródło
i++
i++i
, ale łączy je w tym samym wyrażeniu.Kilka lat temu przeczytałem, że operatorzy ci byli uważani za niebezpiecznych, więc spróbowałem znaleźć więcej informacji na ten temat. Gdyby w tym czasie istniał przepływ stosów, zapytałbym go o to.
Teraz dzieje się tak, ponieważ niektórzy pokręceni ludzie piszą takie pętle jak
Nawet teraz nie jestem zbyt pewien, co się stanie / powinno się zdarzyć, ale jest dla mnie całkiem jasne, że wiele ++ [var] w tej samej linii prosi o kłopoty.
źródło
x = ++j;
są dobrze zdefiniowane w C. Powyższe jest niezdefiniowane, ponieważj
jest modyfikowane dwukrotnie bez pośrednich punktów sekwencji.Dwa powody.
Prawidłową implementacją ++ i jest zwiększenie i, a następnie zwrócenie go. Prawidłową implementacją i ++ jest zapisanie bieżącej wartości, zwiększenie i i zwrócenie zapisanej wartości. Znajomość tych nie jest zaimplementowana, ponieważ synonimy są ważne.
Powstaje zatem pytanie, kiedy kompilator stosuje je podczas oceny wyrażenia, takiego jak równość.
Jeśli test równości jest wykonywany jako pierwszy, to operatorzy przed i po inkrementacji będą musieli napisać inną logikę niż wtedy, gdy najpierw oceniana jest lewa strona (lhs) i prawa strona (rhs), a następnie równość.
Chodzi o kolejność operacji, a to z kolei wpływa na kod, który się pisze. I nie jest zaskakujące, że nie wszystkie języki są zgodne.
Lista testów podstawowych pozwala programistom sprawdzić, czy ich założenia są poprawne, a także czy rzeczywista implementacja jest zgodna ze specyfikacją języka.
Może to mieć różny wpływ na pracę ze wskaźnikami, pętlami lub zwracaniem wartości.
źródło
++i
polega na użyciu wartościi+1
i w pewnym momencie, być może przed lub po tym, ale przed kolejnym punktem sekwencji, przyrostemi
.Myślę, że to szok kulturowy.
Jak już wspomniano, zachowanie wyrażenia w C lub C ++ może być nieokreślone, ponieważ kolejność wykonywania przyrostów itp. Nie jest ściśle określona. Niezdefiniowane zachowanie jest dość powszechne w C i oczywiście wiele z nich zostało zaimportowanych do C ++.
Dla kogoś, kto dokonał programowania w innym języku - kogoś, kto wpadł na pomysł, że języki programowania powinny być precyzyjne i że komputery powinny robić to, co im kazano ... no cóż, szokiem jest odkryć, że C jest celowo niejasny w niektórych kwestiach.
źródło
++
i--
operatory nie były oparte na PDP-11, który nie istniał, gdy operatory te zostały wprowadzone w języku C poprzednika B. Patrz cm.bell-labs.com/who/dmr/chist.html i wyszukaj „auto-inkrement”.Być może po prostu programiści C częściej używają inkrementacji ++ ogólnie - widząc, jak C nie ma „foreach” lub podobnej instrukcji do iteracji przez tablice. Aha, i oczywiście wskaźnik arytmetyki, jak wcześniej wspomniano!
źródło
Różnica między obiema częściami: poczta i wstępne zwiększenie działają tak, jak te dwa fragmenty kodu powinny działać w każdym języku. TO NIE JEST W ZALEŻNOŚCI JĘZYKOWE !!!
To jest przyrost. Ten fragment kodu najpierw zwiększy wartość,
i
zanim wyśle wartość do wiersza, w którym jest używany.To jest przyrost postu. Ten fragment kodu zwróci wartość,
i
zanim zwiększy wartośći
w wierszu, w którym jest używany.W innym małym przykładzie:
Ten kod kompiluje się z wynikami na codepad.
Ma to związek z wewnętrzną implementacją przeciążenia operatora.
++i
bezpośrednio zwiększa wartość (i dlatego jest nieco szybszy)i++
najpierw tworzy kopię, która jest zwracana tam, gdzie jest potrzebna, a następnie pierwotna wartośći
zmiennej jest zwiększana o jeden.Mam nadzieję, że teraz jest to jasne.
źródło
++i
nie jest szybszy ii++
nie tworzy kopii. Ponadto++i
zachowuje się nieco inaczej w C niż w C ++, nie mówiąc już o innych językach.