Jestem programistą-samoukiem, na wypadek, gdyby na to pytanie udzielono odpowiedzi w CS 101. Nauczyłem się i używałem wielu języków, głównie na własny użytek, ale czasami do rzeczy profesjonalnych.
Wygląda na to, że zawsze napotykam na tę samą ścianę, kiedy mam problemy z programowaniem. Na przykład właśnie zadałem pytanie na innym forum, w jaki sposób obsługiwać wskaźnik do tablicy zwrócony przez funkcję. Początkowo myślę, że po prostu nie znam właściwej techniki, którą projektanci C ++ ustawili, aby poradzić sobie z sytuacją. Ale z odpowiedzi i dyskusji, które następują, widzę, że tak naprawdę nie rozumiem, co się dzieje, gdy coś jest „zwracane”.
Jak głęboki poziom zrozumienia procesu programowania musi osiągnąć dobry programista?
Odpowiedzi:
Nie. Nikt nie rozumie, co się dzieje na poziomie sprzętowym.
Systemy komputerowe są jak cebula - istnieje wiele warstw, a każda z nich zależy od warstwy pod nią do wsparcia. Jeśli jesteś facetem pracującym na jednej z zewnętrznych warstw, nie powinieneś zbytnio przejmować się tym, co dzieje się w środku cebuli. I to dobrze, ponieważ środek cebuli zawsze się zmienia. Tak długo, jak warstwa lub warstwy, które obsługują daną warstwę, nadal wyglądają tak samo i obsługują warstwę, jesteś dobry.
Ale potem znowu...
Tak. To znaczy, nie musisz rozumieć, co naprawdę dzieje się wewnątrz cebuli, ale bardzo pomaga mieć mentalny model tego, jak wygląda wnętrze typowej cebuli. Być może nie najgłębsza część, w której masz bramki złożone z tranzystorów i tak dalej, lub następna warstwa lub dwie, gdzie masz mikrokod, zegar, jednostki dekodujące instrukcje itp. Jednak kolejne warstwy są tam, gdzie Mam rejestry, stos i stos. Są to najgłębsze warstwy, na które masz duży wpływ na to, co się dzieje - kompilator tłumaczy Twój kod na instrukcje działające na tym poziomie, a jeśli chcesz, zwykle możesz przejść przez te instrukcje i dowiedzieć się, co się naprawdę dzieje.
Najbardziej doświadczeni programiści mają w głowie nieco bajkową wersję tych warstw. Pomagają zrozumieć, o czym mówi kompilator, gdy mówi, że wystąpił „wyjątek nieprawidłowego adresu” lub „błąd przepełnienia stosu” lub coś podobnego.
Jeśli jesteś zainteresowany, przeczytaj książkę o architekturze komputera. Nie musi to być nawet szczególnie nowa książka - komputery cyfrowe działają od dłuższego czasu w podobny sposób. Im więcej dowiesz się o wnętrzu cebuli, tym bardziej będziesz zdumiony, że którekolwiek z tych rzeczy w ogóle działa! Uczenie się (w przybliżeniu) tego, co dzieje się w niższych warstwach, sprawia, że programowanie jest zarówno mniej tajemnicze, jak i bardziej magiczne. I naprawdę więcej zabawy.
Inną rzeczą, na którą możesz spojrzeć, jest osadzona cebula. Mam na myśli systemy wbudowane. Istnieje wiele wbudowanych platform, które są dość łatwe w użyciu: Arduino i BASIC Stamp to dwa przykłady. Są to w zasadzie małe mikroprocesory z wieloma wbudowanymi funkcjami. Możesz myśleć o nich jak o cebuli z mniejszą ilością warstw niż w typowym komputerze stacjonarnym, więc możesz dokładnie zrozumieć, co dzieje się w całym systemie, od sprzętu po oprogramowanie.
źródło
Nie mówisz o poziomie sprzętu, mówisz o tym, co kompilator naprawdę robi z tym, co mu nakazujesz.
Z pewnością potrzebujesz takiego poziomu zrozumienia, aby dowiedzieć się, co poszło nie tak, gdy nie jest to oczywiste, szczególnie w przypadku sytuacji, w której następuje utrata pamięci.
źródło
Zrozumienie pamięci programu! = Zrozumienie sprzętu
Zrozumienie hierarchii pamięci == Zrozumienie sprzętu
Aby odpowiedzieć na ogólne pytanie: To zależy. Zrozumienie sprzętu nie zaszkodzi, ale zrozumienie go nie pomoże we wszystkich przypadkach.
Na podstawie Twojego przykładu, musisz tylko dowiedzieć się więcej o tym, jak pamięć jest dzielona i jak jest zorganizowana podczas uruchamiania programu. Zrozumienie sprzętu nie pomoże ci w tym zakresie, ponieważ pamięć (widoczna dla programu) nawet nie reprezentuje sprzętu dzięki magii pamięci wirtualnej.
Gdybyś był ciekawy problemów z wydajnością w oparciu o kolejność uzyskiwania dostępu do pamięci, TERAZ skorzystałbyś na zrozumieniu sprzętu, dziedziczności pamięci, brakach pamięci podręcznej, błędach strony i całej chwalebnej wspaniałości, która pochodzi ze sprzętu.
źródło
Jeśli nie zdecydujesz się nauczyć trochę asemblerze, powinieneś nauczyć się czegoś podobnego asemblerze 6502 na Commodore 64 (emulowane, oczywiście), lub 68000 na Amidze.
Możesz dowiedzieć się więcej o Commodore 64 tutaj ...
http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main
Klasyczna książka, którą musisz znać, to ta opisana tutaj ...
http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/
Prawdopodobnie możesz znaleźć skan PDF, jeśli się rozejrzysz.
IMO, 6502 jest łatwiejszy niż Z80, a 68000 jest łatwiejszy niż 8086 - bardziej regularne zestawy instrukcji itp.
Ale procesor jest tylko jednym aspektem sprzętu. Ponadto nowoczesny procesor jest ogromnie inną bestią i robi rzeczy, które są przezroczyste nawet z punktu widzenia kompilatorów - na przykład przedstawia wirtualną przestrzeń adresową.
Szczególną zaletą 6502 na C64 jest to, że procesor jest nie tylko prosty, ale także bardzo prosty do zhackowania ze sprzętem. Kiedyś świetnie się bawiłem, grając z chipem muzycznym SID.
Więc - prawdopodobnie jest to cenne ćwiczenie, jeśli nie spędzasz na nim zbyt wiele czasu. Nauczyłem się asemblera 6502 jako mojego drugiego języka, kiedy miałem około 14 lat, zaraz po Commodore Basic. Ale przede wszystkim uzyskuje się ten bardzo prosty działający model, dzięki czemu można dodawać do niego bardziej wyrafinowane pomysły przy minimalnym nieporozumieniu.
Kilka przydatnych rzeczy, których możesz nauczyć się pracując w asemblerze ...
Jednym szczególnym powodem, dla którego polecam, jest lepsze zrozumienie sposobu, w jaki proste kroki działają całkowicie deterministycznie, mechanicznie i całkowicie bez inteligencji i zdrowego rozsądku. Zasadniczo przyzwyczajanie się do imperatywnego modelu wykonania w jego najczystszej i najbardziej upartej niewiedzy.
Dokładne pytanie, jak przydatna jest wiedza o większości tych rzeczy, jest jednak trudnym pytaniem.
Jednej rzeczy nie nauczysz się, jak dobrze grać z dziedzicznością pamięci. Te stare maszyny miały w większości prosty model pamięci bez warstw pamięci podręcznej i pamięci wirtualnej. Nie dowiesz się też wiele na temat współbieżności - były to z pewnością sposoby, aby sobie z tym poradzić, ale w większości oznaczały to przerwy. Nie musiałeś się martwić muteksami itp.
Czasami mentalny model tego, jak kiedyś działały te rzeczy lub jak działa asembler, może nawet wprowadzić w błąd. Na przykład myślenie o wskaźniku C jako adresie może prowadzić do nieokreślonych problemów z zachowaniem. Wskaźnik AC jest zwykle implementowany jako liczba całkowita zawierająca adres, ale nie ma gwarancji, że jest to absolutnie prawda. Na przykład na niektórych dziwnych platformach różne wskaźniki mogą wskazywać na różne przestrzenie adresowe. Staje się to ważne, gdy chcesz wykonać arytmetykę lub logikę bitową za pomocą dwóch wskaźników.
Jeśli nie masz jednej z tych dziwacznych platform, możesz nie myśleć, że ci na tym zależy - ale w dzisiejszych czasach kompilatory coraz częściej wykorzystują do optymalizacji zachowanie niezdefiniowane przez standardy.
Tak więc mentalny model architektury systemu może być przydatny, ale nadal ważne jest, aby kodować zgodnie ze specyfikacją języka, a nie hipotetycznym modelem, którego język i platforma mogą nie respektować.
Wreszcie, wiele przydatnych rzeczy z modelu mentalnego pochodzi z poznania, w jaki sposób kompilatory generują kod - a generowanie kodu dla współczesnych języków różni się bardzo od dość trywialnych kompilatorów dostępnych wówczas.
To moja ulubiona książka do tego ...
http://dickgrune.com/Books/MCD_1st_Edition/
Oprócz zagadnień związanych z analizowaniem składni, AST itp., Obejmuje generowanie kodu dla szeregu paradygmatów językowych - imperatywny, OOP, funkcjonalny, logiczny, równoległy i rozproszony - a także do zarządzania pamięcią. Jeśli chcesz wiedzieć, jak działają metody polimorficzne bez zagłębiania się w szczegóły zestawu instrukcji procesora, książka taka jak ta jest twoją przyjaciółką - wkrótce pojawi się nowe wydanie.
źródło
Dwadzieścia lat temu było to ważne, ale nie tak bardzo teraz - istnieje znacznie więcej warstw abstrakcji między oprogramowaniem a nowoczesnym sprzętem.
Warto wiedzieć, jak potrzeba wielu wątków, aby skorzystać z wielu rdzeni lub że użycie większej ilości pamięci niż w systemie jest złą rzeczą, ale poza tym tak naprawdę jej nie potrzebujesz, chyba że Twoim zadaniem jest napisanie tych abstrakcji warstwy.
Reszta twojego pytania sugeruje, że możesz być bardziej zainteresowany kompilatorem niż sprzętem, co jest nieco inne. Możesz natknąć się na przypadki, w których jest to ważne, ale zwykle są to albo trywialne (nieskończona rekurencja nie działa zbyt dobrze), albo rodzaj skrajnych przypadków, w których możesz czuć się dobrze, rozwiązując je, ale prawdopodobnie nigdy nie napotkasz tego samego problemu jeszcze raz.
źródło
Bardzo pomaga poznać i zrozumieć abstrakcję przedstawioną przez sprzęt, a trochę ogólnego pojęcia o tym, jak powstaje ta iluzja - ale próba prawdziwego zrozumienia, jak naprawdę działa nowoczesny sprzęt, to ogrom pracy, z której „ prawdopodobnie zobaczą tylko minimalny zwrot.
Jeśli wybaczysz drobną rozrywkę: przypomina mi to coś, co zauważyłem kilka lat temu. Kilkadziesiąt lat temu (do końca lat siedemdziesiątych) większość ludzi uważała, że komputery były o krok od magii - prawie nie podlegały prawom fizyki, zdolne do wszelkiego rodzaju rzeczy, które nie miały większego sensu i tak dalej. W tym czasie spędziłem sporo czasu próbując (przeważnie bezskutecznie) przekonać ludzi, że nie, nie byli magią. Były to naprawdę dość zwyczajne maszyny, które wykonywały ograniczoną liczbę rzeczy bardzo szybko i niezawodnie, ale poza tym były wyjątkowo przyziemne.
W dzisiejszych czasach zmieniło się postrzeganie komputerów przez większość ludzi. Są teraz dość zwyczajni - do tego stopnia, że całkiem sporo zwykłych ludzi ma ich praktyczną wiedzę. Na przykład, jakiś czas temu, kiedy jadłem kolację, widziałem / słyszałem kelnera i kelnerkę podczas ich przerwy, omawiających, co powinna dostać w swoim nowym komputerze. Porady, których udzielał, były całkowicie rozsądne i realistyczne.
Moje spojrzenie na komputery też się zmieniło. Poszedłem do Hot Chips, a wcześniej Forum Mikroprocesorów sięga około połowy lat 90-tych. I zapewne wie więcej na temat sprzętu mikroprocesora niż co najmniej 99% programistów - i wiedząc, co zrobić, powiem tak: oni nie już zwyczajne. Oni mają prawie łamać prawa fizyki. Przeprowadziłem wiele testów na niskim poziomie i mogę to powiedzieć na pewno: przekroczenie iluzji stworzonej przez procesor i przejście do poziomu pokazania, jak naprawdę działa sprzęt, jest często niezwykle trudne. Chciałbym móc zamieścić zdjęcie jednego z naszych ustawień z komputerem ukrytym pod kablami z co najmniej 4 analizatorów logicznych, aby właściwie zmierzyć jeden aspekt tego, jak buforowanie działa na nowoczesnym procesorze (nie wspominając o niektórych naprawdę wybrednych programach, aby upewnić się, że to, co zmierzyliśmy, było dokładnie tym, co robił procesor i nic więcej).
źródło
Różne języki działają na różnych poziomach abstrakcji od sprzętu. C i C ++ są na bardzo niskim poziomie. Z drugiej strony języki skryptowe wymagają mniejszej wiedzy na temat podstawowych szczegółów.
Jednak nadal powiedziałbym, że we wszystkich przypadkach, im więcej wiesz, tym lepiej będziesz programistą. Część programowania polega na jednoczesnym żonglowaniu wieloma poziomami abstrakcji.
Jeśli programujesz w C ++, musisz całkiem dobrze zrozumieć, jak działa nowoczesny procesor, przynajmniej na poziomie abstrakcji, na którym działa kompilator. (Wewnątrz procesora dzieją się rzeczy, które są przezroczyste dla kompilatora).
źródło
Chciałbym dodać punkt o ogólnym projekcie języków wyższego poziomu, takich jak C.
Ogólnie rzecz biorąc, myślę, że można bezpiecznie powiedzieć, że takie języki można postrzegać jako implementację abstrakcyjnej maszyny, i tak właśnie sam Dennis Ritchie opisał, jak działa C i jak szczególny projekt abstrakcyjnej maszyny C uczynił z niej bardziej przenośny język. W związku z tym pewne zrozumienie architektury komputera i działania na poziomie maszyny może być niezwykle pomocne w zrozumieniu abstrakcyjnej maszyny języka.
Artykuł DMR Przenośność programów C i systemu UNIX jest pierwszym, jaki pamiętam, aby omówić (abstrakcyjny) model maszyny dla C.
Myślę, że artykuł DMR na temat historii i rozwoju języka C jest również niezwykle przydatny do pokazania, w jaki sposób rzeczywisty sprzęt wpływa na projektowanie języka, i być może jest również przykładem wczesnego projektowania języka programowania: Rozwój języka C
źródło