Wierzę, że C jest dobrym językiem do nauki zasad programowania. Czego możesz się nauczyć w językach niższego poziomu, które są „magiczne” od języków wysokiego poziomu, takich jak Ruby?
Wierzę, że C jest dobrym językiem do nauki zasad programowania. Czego możesz się nauczyć w językach niższego poziomu, które są „magiczne” od języków wysokiego poziomu, takich jak Ruby?
Odpowiedzi:
Nie ma zasad, w ogólnym abstrakcyjnym znaczeniu informatyki, które są obecne w C, które nie są również obecne w językach wyższego poziomu. Cała informatyka sprowadza się do algorytmów, a wszystkie algorytmy można zaimplementować w dowolnym języku, który jest Turing-zupełny jak C.
Różnica, którą C przenosi poza języki wyższego poziomu, jest podobna do różnicy, którą kod maszynowy niesie poza C: Relacja maszyny do kodu.
Pisząc kod w językach wysokiego poziomu, nie musisz (ogólnie) martwić się interakcją kodu z maszyną. Maszyna wirtualna zdefiniowana przez język ukrywa wiele z tych aspektów wykonywania kodu.
W C interakcja twojego programu z pamięcią jest na pierwszym planie. To więcej niż tylko to, że musisz zarządzać wykorzystaniem sterty, obejmuje ona interakcję kodu ze stosem oraz sposób, w jaki sam dostęp pamięci do kodu wpływa na zachowanie i wydajność kodu - nawet na kolejność dostępu do pamięci można uniknąć uwagi, ponieważ czytanie niewłaściwej pamięci w niewłaściwym czasie może skutecznie osłabić wydajność.
W językach wyższego poziomu te rzeczy nie są tak oczywiste. Pamięć jest przydzielana i zwalniana bez Twojej wiedzy, a czasem bez Twojej prośby. Najczęściej jest to po prostu poza twoją kontrolą. Kiedy, gdzie, jak i dlaczego większość przydziałów pamięci jest po prostu ukryta przed tobą.
Podobnie, w innym kierunku, pisanie kodu maszynowego lub kodu asemblera przynosi jeszcze więcej szczegółów na pierwszy plan: prawie nic nie pozostaje poza twoim zakresem, a twój kod musi być napisany z uwzględnieniem każdej alokacji, każdego zasobu, każdej przekazywanej części danych poprzez rejestry procesora - wiedza tak daleko od języków wysokiego poziomu, że jest tajemna.
Wiem, że C jest dobrym językiem do nauki zasad programowania.
Nie zgadzam się. C nie ma zbyt wielu funkcji, aby nauczyć się zasad programowania. Funkcje C do tworzenia abstrakcji są okropne, a abstrakcja jest jedną z kluczowych zasad programowania.
Jeśli chcesz się dowiedzieć, jak działa sprzęt, a co za tym idzie mechanicznej sympatii do maszyny, powinieneś nauczyć się kodu maszynowego, czyli architektury zestawu instrukcji, a także przestudiować budowę pamięci podręcznej nowoczesnych procesorów. Zauważ, że nie polecam języka asemblera, po prostu zapoznaj się z instrukcjami sprzętowymi, aby zrozumieć, co generuje kompilator.
Jeśli chcesz nauczyć się zasad programowania, użyj nowoczesnego języka, takiego jak Java, C # lub Swift, lub jednego z wielu innych, takich jak Rust. Studiuj także różne rodzaje paradygmatów programowania, w tym funkcjonalne.
Większość języków programowania jest opisywana w kategoriach abstrakcyjnych maszyn. Następnie są one wdrażane przy użyciu zestawów narzędzi, takich jak kompilatory, konsolidatory, asemblery, interpretery, analizatory statyczne, języki pośrednie i sprzęt , które wspólnie wygenerują wynik, który honoruje co najmniej wszystkie oczekiwane zachowanie maszyny abstrakcyjnej, zaobserwowane przez program .
C nie jest wyjątkiem od powyższej reguły. Jest to opisane jako abstrakcyjna maszyna, która nie ma pojęcia o twoim rzeczywistym sprzęcie.
Jako takie, gdy ludzie mówią, że C uczy cię, jak naprawdę działa komputer, zwykle oznaczają, że C uczy, jak działa C. Ale C, ponieważ jest tak wszechobecny w programowaniu systemów, jest zrozumiałe, że wiele osób zaczyna mylić go z samym komputerem. I osobiście posunąłbym się nawet do stwierdzenia, że wiedza o tym, jak działa C, jest często ważniejsza niż wiedza o tym, jak działa sam komputer.
Ale C i komputer to różne rzeczy. Rzeczywisty sprzęt jest w rzeczywistości skomplikowany - w taki sposób, że specyfikacja C jest czytana jak książka dla dzieci. Jeśli jesteś zainteresowany działaniem twojego sprzętu, zawsze możesz poszukać instrukcji i zacząć pisać kod w asemblerze. Lub zawsze możesz zacząć uczyć się o obwodach cyfrowych, aby móc samodzielnie zaprojektować sprzęt. (Przynajmniej docenisz, jak wysoki jest poziom C.)
Okay, właściwie nauka o sprzęcie obejmuje rzeczy inne niż C. Ale czy C może dzisiaj uczyć programistów czegoś innego?
Myślę, że to zależy.
Nie bądź zbyt szybki, aby wybrać jedną z tych możliwości. Piszę kod od wielu lat i nadal nie mam pojęcia, która z nich jest poprawna, ani czy poprawna odpowiedź jest tylko jedną z dwóch, czy też istnieje coś takiego jak poprawna odpowiedź w tej sprawie.
Nie jestem skłonny wierzyć, że prawdopodobnie powinieneś ostatecznie zastosować obie opcje, w luźnej kolejności, w której je opisałem. Ale nie sądzę, że to naprawdę kwestia techniczna, myślę, że ma ona głównie charakter edukacyjny. Wydaje się, że każda osoba uczy się na różne sposoby.
Jeśli odpowiedziałeś na powyższe pytanie przynajmniej przez włączenie drugiej opcji, którą zaproponowałem, masz już kilka odpowiedzi: wszystko, czego można się nauczyć w językach wyższego poziomu, można lepiej nauczyć poprzez ponowne wynalezienie go w C lub w najmniej rozwinięty przez dodanie C do miksu.
Ale bez względu na odpowiedź z pewnością jest kilka rzeczy, których możesz nauczyć się prawie wyłącznie z języka C (i być może kilku innych języków).
C jest historycznie ważne. Jest to kamień milowy, na który możesz spojrzeć i docenić, skąd pochodzimy, i może uzyskać nieco więcej kontekstu na temat tego, dokąd zmierzamy. Możesz docenić, dlaczego istnieją pewne ograniczenia i możesz zrozumieć, że pewne ograniczenia zostały zniesione.
C może nauczyć cię pracy w niebezpiecznych warunkach. Innymi słowy, może wyszkolić cię do pilnowania, gdy język (dowolny język) nie może lub nie zrobi tego za ciebie, z jakiegokolwiek powodu. Może to sprawić, że będziesz lepszym programistą nawet w bezpiecznych środowiskach, ponieważ sam wygenerujesz mniej błędów i ponieważ będziesz mógł tymczasowo wyłączyć bezpieczeństwo, aby wycisnąć dodatkową prędkość z twojego bezpiecznego programu (np. Użycie wskaźników w języku C #), w przypadkach, w których bezpieczeństwo wiąże się z kosztami środowiska wykonawczego.
C może nauczyć cię, że każdy obiekt ma wymagania dotyczące pamięci, układ pamięci, fakt, że do pamięci można uzyskać dostęp za pośrednictwem skończonej przestrzeni adresowej i tak dalej. Podczas gdy inne języki nie wymagają Twojej uwagi w tych sprawach, istnieje kilka przypadków, w których nabyta intuicja może pomóc w podejmowaniu bardziej świadomych decyzji.
C może uczyć cię o szczegółach plików łączących i obiektowych oraz innych zawiłościach poprzez swój system kompilacji. Może to pomóc w praktycznym zrozumieniu, w jaki sposób natywnie skompilowany program często przechodzi od kodu źródłowego do wykonania.
C może skłonić twój umysł do myślenia w nowatorski sposób poprzez koncepcję niezdefiniowanego zachowania. Nieokreślone zachowanie jest jednym z moich ulubionych pojęć w tworzeniu oprogramowania, ponieważ badanie jego wpływu na nieklasyczne kompilatory jest unikalnym ćwiczeniem umysłowym, którego nie można całkiem zrozumieć z innych języków. Musisz jednak odrzucić próbę i błąd i zacząć uczyć się języka w ostrożny i celowy sposób, zanim w pełni docenisz ten aspekt.
Ale być może najważniejszą realizacją, jaką C może ci dać, będąc małym językiem, jest idea, że całe programowanie sprowadza się do danych i operacji . Możesz spojrzeć na rzeczy jako na klasy modułowe z hierarchiami i interfejsami z wirtualną wysyłką lub na eleganckie niezmienne wartości, które są obsługiwane przy użyciu czysto matematycznych funkcji. I to wszystko w porządku - ale C przypomni Ci, że to wszystko tylko operacje na danych . Jest to przydatny sposób myślenia, ponieważ pozwala znieść wiele barier mentalnych.
Powodem, dla którego C jest dobry do nauki, nie jest to, że uczy on jakichkolwiek zasad . Uczy cię, jak to działa .
C można porównać z jednym z tych dobrych, dobrych samochodów z lat 70. lub 80., które właśnie zbudowano do jazdy. Możesz je rozerwać, przykręcić śrubą i zrozumieć, jak działa każda część, i jak to działa razem z innymi częściami, które możesz wziąć w swoje ręce, aby na nie spojrzeć. Po zrozumieniu wszystkich części masz bardzo jasny obraz tego, jak działa całość.
Współczesne języki są bardziej jak nowoczesny samochód, w którym silnik jest w zasadzie czarną skrzynką, co jest zbyt skomplikowane, aby zrozumieć go przeciętny właściciel samochodu. Te samochody mogą wiele zdziałać, do diabła, w tych dniach aktywnie uczą się jeździć samodzielnie. A przy tej złożoności i komforcie interfejs użytkownika został znacznie przesunięty w stosunku do tego, co faktycznie dzieje się w silniku.
Kiedy uczysz się programowania w C, masz do czynienia z wieloma śrubami i nakrętkami, z których składa się komputer. To pozwala rozwinąć zrozumienie samej maszyny. Na przykład pozwala zrozumieć, dlaczego nie jest dobrym pomysłem budowanie długiego łańcucha:
java.lang.String result = "";
for(int i = 0; i < components.size; i++) {
result = result + components[i];
};
(Mam nadzieję, że to jest poprawna Java, nie używałem jej od dłuższego czasu ...) Z tego przykładu kodu nie jest oczywiste, dlaczego pętla ma kwadratową złożoność. Ale tak właśnie jest i jest to powód, dla którego ten kod przestanie działać, gdy masz kilka milionów małych komponentów do połączenia. Doświadczony programista C natychmiast wie, gdzie jest problem i prawdopodobnie uniknie pisania takiego kodu w pierwszej kolejności.
for(int i = 0; i < strlen(s); i++)
w C, pętla będzie miała kwadratową złożoność i jest tak samo nieoczywista jak w twoim przykładzie Java ;-)
Są lepsze języki niż C do nauki „zasad programowania”, zwłaszcza zasad teoretycznych, ale C może być dobrym rozwiązaniem, aby nauczyć się kilku praktycznych, ważnych rzeczy na temat rzemiosła. Odpowiedź greyfade jest z pewnością poprawna, ale IMHO może nauczyć się więcej od C niż samodzielne zarządzanie pamięcią. Na przykład,
jak tworzyć programy z pełną obsługą błędów przy braku wyjątków
jak stworzyć strukturę w programie bez obsługi języka dla orientacji obiektowej
jak radzić sobie z danymi przy braku struktur danych, takich jak dynamiczne, spore listy, słowniki lub przydatna abstrakcja ciągów
jak uniknąć typowych błędów, takich jak przepełnienie tablicy, nawet jeśli kompilator lub środowisko wykonawcze nie ostrzega automatycznie
jak tworzyć ogólne rozwiązania bez obsługi języka dla szablonów lub ogólnych
i czy wspominałem, że możesz nauczyć się samodzielnie zarządzać pamięcią? ;-)
Ponadto, ucząc się języka C, dowiesz się, skąd biorą się podobieństwa składniowe C ++, Java, C #, Cel C.
W 2005 roku Joel Spolsky napisał zalecenie dotyczące nauki języka C przed jakimkolwiek innym językiem wyższego poziomu. Jego argumenty są
„nigdy nie będziesz w stanie stworzyć wydajnego kodu w językach wyższego poziomu”.
„Nigdy nie będziesz w stanie pracować na kompilatorach i systemach operacyjnych, które są jednymi z najlepszych zadań programistycznych.”
„Nigdy nie będziesz mieć zaufania do tworzenia architektur dla dużych projektów”
„jeśli nie potrafisz wyjaśnić, dlaczego while(*s++ = *t++);
kopiujesz ciąg znaków lub jeśli nie jest to dla ciebie najbardziej naturalne na świecie, programujesz na podstawie przesądów
Oczywiście to, co napisał, jest z pewnością dyskusyjne, ale wiele jego argumentów IMHO jest nadal aktualnych.
Dwie podstawowe abstrakcje obliczeń to maszyny Turinga i rachunek Lambda, a C to sposób na eksperymentowanie z widokiem maszyny obliczeń Turinga: głównie seria działań na niskim poziomie, z których wynika pożądany rezultat. Trzeba jednak pamiętać, że C ma własny model obliczeń. Zatem nauka języka C nauczy Cię szczegółów niskiego poziomu maszyny abstrakcyjnej C, która różni się od rzeczywistych architektur. Jedną z pierwszych rzeczy, których nauczyłem się w C, było nigdy nie przechytrzenie kompilatora przez zastosowanie „sprytnych” sztuczek i wydaje się, że trendem jest coraz większa optymalizacja kompilatorów. Podobnie jak w innych językach wysokiego poziomu, podczas pisania w języku C kompilatory rozumieją, czego oczekujesz na abstrakcyjnej maszynie C i sprawiają, że dzieje się to na rzeczywistym sprzęcie,
Mam na myśli to, że nauka języka C niekoniecznie da ci dobry obraz tego, co faktycznie dzieje się w sprzęcie. „C jest blisko maszyny” należy rozumieć jako „bliżej niż większość języków wyższego poziomu”. Bezpośrednie uczenie się architektury oprogramowania będzie bardziej opłacalne, jeśli chcesz uzyskać dokładniejszy obraz „tego, jak to działa”.
Z drugiej strony nauka języka C może zaznajomić się z programowaniem systemu, typami niskiego poziomu, wskaźnikami, a zwłaszcza alokacją pamięci. Jeśli chodzi o algorytmy uczenia się i strukturę danych, nie ma przewagi, aby nauczyć się ich w języku C niż w innych językach.
To bardzo otwarte pytanie, może nie dać rozstrzygającej odpowiedzi. Możesz nauczyć się prawie wszystkiego w każdym języku, pod warunkiem, że znasz wewnętrzne ramy językowe. C zmusza Cię do zrozumienia niższych szczegółów, ponieważ został zaprojektowany przede wszystkim do napisania systemu operacyjnego. Nawet po tylu latach wciąż jest jednym z najczęściej używanych języków, przede wszystkim dzięki systemom wbudowanym i projektom open source. Pytanie brzmi: czego chcesz się nauczyć? A w jakiej domenie?