Rozważam naukę C.
Ale dlaczego ludzie używają C (lub C ++), jeśli można go używać „niebezpiecznie”?
Przez niebezpieczne rozumiem wskaźniki i inne podobne rzeczy.
Jak pytanie o przepełnienie stosu Dlaczego funkcja gets jest tak niebezpieczna, że nie należy jej używać? . Dlaczego programiści nie używają tylko Java, Python lub innego skompilowanego języka, takiego jak Visual Basic?
Odpowiedzi:
C wyprzedza wiele innych języków, o których myślisz. Wiele z tego, co wiemy o tym, jak uczynić programowanie „bezpieczniejszym”, pochodzi z doświadczenia z językami takimi jak C.
Wiele bezpieczniejszych języków, które pojawiły się od czasu C, polega na większym środowisku wykonawczym, bardziej skomplikowanym zestawie funkcji i / lub maszynie wirtualnej do osiągnięcia swoich celów. W rezultacie C pozostało czymś w rodzaju „najniższego wspólnego mianownika” wśród wszystkich popularnych / popularnych języków.
C jest znacznie łatwiejszym językiem do implementacji, ponieważ jest stosunkowo mały i ma większe szanse na odpowiednią wydajność nawet w najsłabszym środowisku, więc wiele systemów wbudowanych, które muszą opracować własne kompilatory i inne narzędzia, jest w stanie zapewnić funkcjonalny kompilator dla C.
Ponieważ C jest tak mały i tak prosty, inne języki programowania mają tendencję do komunikowania się ze sobą za pomocą API typu C. Jest to prawdopodobnie główny powód, dla którego C nigdy tak naprawdę nie umrze, nawet jeśli większość z nas kiedykolwiek wejdzie z nim w interakcję poprzez opakowania.
Wiele „bezpieczniejszych” języków, które starają się ulepszyć w C i C ++, nie próbuje być „językami systemowymi”, które dają prawie całkowitą kontrolę nad wykorzystaniem pamięci i zachowaniem się programu w czasie wykonywania. Chociaż prawdą jest, że coraz więcej aplikacji w dzisiejszych czasach po prostu nie potrzebuje takiego poziomu kontroli, zawsze będzie kilka drobnych przypadków, w których jest to konieczne (szczególnie w maszynach wirtualnych i przeglądarkach, które implementują te wszystkie ładne, bezpieczne języki dla reszta z nas).
Obecnie istnieje kilka języków programowania systemów (Rust, Nim, D, ...), które są bezpieczniejsze niż C lub C ++. Mają korzyści z perspektywy czasu i zdają sobie sprawę, że w większości przypadków taka dokładna kontrola nie jest potrzebna, dlatego oferują ogólnie bezpieczny interfejs z kilkoma niebezpiecznymi zaczepami / trybami, które można przełączać, gdy jest to naprawdę konieczne.
Nawet w obrębie C nauczyliśmy się wielu zasad i wytycznych, które drastycznie zmniejszają liczbę podstępnych błędów, które pojawiają się w praktyce. Zasadniczo niemożliwe jest wprowadzenie w życie tych reguł z mocą wsteczną, ponieważ spowodowałoby to uszkodzenie zbyt wiele istniejącego kodu, ale powszechne jest używanie ostrzeżeń kompilatora, linters i innych narzędzi do analizy statycznej w celu wykrycia tego rodzaju problemów, którym można łatwo zapobiec. Podzbiór programów C, które przekazują te narzędzia w jaskrawych kolorach, jest już znacznie bezpieczniejszy niż „tylko C”, a każdy kompetentny programista C w tych dniach będzie z nich korzystać.
Ponadto, nigdy nie dokona ukrywane konkurs Java jako zabawne jak ukrywane konkursie C .
źródło
Po pierwsze, C jest językiem programowania systemów. Na przykład, jeśli napiszesz maszynę wirtualną Java lub interpreter Pythona, będziesz potrzebować systemowego języka programowania, aby ją napisać.
Po drugie, C zapewnia wydajność, której nie zapewniają języki takie jak Java i Python. Zazwyczaj wysokowydajne obliczenia w Javie i Pythonie wykorzystują biblioteki napisane w języku o wysokiej wydajności, takim jak C, do ciężkiego podnoszenia.
Po trzecie, C ma znacznie mniejszą powierzchnię niż języki takie jak Java i Python. Dzięki temu można go używać w systemach wbudowanych, które mogą nie mieć zasobów niezbędnych do obsługi dużych środowisk wykonawczych i wymagań dotyczących pamięci w językach takich jak Java i Python.
„Systemowy język programowania” to język odpowiedni do budowania systemów o sile przemysłowej; w obecnej formie Java i Python nie są językami programowania systemowego. „Dokładnie to, co sprawia, że systemowy język programowania” nie wchodzi w zakres tego pytania, ale systemowy język programowania musi zapewniać wsparcie w pracy z platformą bazową.
Z drugiej strony (w odpowiedzi na komentarze) systemowy język programowania nie musi być hostem własnym. Ten problem pojawił się, ponieważ oryginalny zadawane pytanie „dlaczego ludzie używają C”, pierwszy komentarz pytanie „dlaczego trzeba język jak C”, gdy masz pypy, i zauważył, że pypy ma w rzeczywistości użyć C tak, to był pierwotnie istotny dla pytania, ale niestety (i myląco) „samodzielne hostingowanie” w rzeczywistości nie ma znaczenia dla tej odpowiedzi. Przepraszam, że o tym wspomniałem.
Podsumowując: Java i Python nie nadają się do programowania systemów nie dlatego, że ich podstawowe implementacje są interpretowane, ani dlatego, że natywnie skompilowane implementacje nie są hostowane, ale dlatego, że nie zapewniają niezbędnej obsługi do pracy z platformą bazową.
źródło
Przykro mi, że dodałem jeszcze jedną odpowiedź, ale nie sądzę, aby którakolwiek z istniejących odpowiedzi bezpośrednio dotyczyła pierwszego zdania, stwierdzając:
Dlaczego? Czy chcesz robić rzeczy, do których zwykle używa się obecnie C (np. Sterowniki urządzeń, maszyny wirtualne, silniki gier, biblioteki multimediów, systemy osadzone, jądra systemu operacyjnego)?
Jeśli tak, to tak, na pewno naucz się C lub C ++ w zależności od tego, kim jesteś zainteresowany. Czy chcesz się tego nauczyć, aby lepiej zrozumieć, co robi Twój język wysokiego poziomu?
Następnie wspomnij o obawach dotyczących bezpieczeństwa. Nie musisz dogłębnie rozumieć bezpiecznego C, aby zrobić to drugie, w taki sam sposób, jak przykład kodu w języku wyższego poziomu może dać ci sedno bez gotowości do produkcji.
Napisz kod C, aby uzyskać sedno. Następnie odłóż go z powrotem na półkę. Nie przejmuj się zbytnio bezpieczeństwem, chyba że chcesz napisać produkcyjny kod C.
źródło
To jest OGROMNE pytanie z mnóstwem odpowiedzi, ale krótka wersja jest taka, że każdy język programowania specjalizuje się w różnych sytuacjach. Na przykład JavaScript dla stron internetowych, C dla rzeczy niskiego poziomu, C # dla czegokolwiek w systemie Windows itp. Pomaga wiedzieć, co chcesz robić, kiedy znasz programowanie i decydujesz, który język programowania wybrać.
Aby odnieść się do ostatniego punktu, dlaczego C / C ++ w Javie / Python, często sprowadza się do szybkości. Tworzę gry, a Java / C # ostatnio osiągają prędkości wystarczające do uruchomienia gier. W końcu, jeśli chcesz, aby Twoja gra działała z szybkością 60 klatek na sekundę i chcesz, aby gra dużo (renderowanie jest szczególnie kosztowne), musisz uruchomić kod tak szybko, jak to możliwe. Python / Java / C # / Wiele innych działa na „interpreterach”, dodatkowej warstwie oprogramowania, która obsługuje wszystkie żmudne rzeczy, których nie obsługuje C / C ++, takie jak zarządzanie pamięcią i wyrzucanie elementów bezużytecznych. To dodatkowe obciążenie spowalnia działanie, więc prawie każda duża gra, którą widzisz, została wykonana (w każdym razie przez ostatnie 10 lat) w C lub C ++. Istnieją wyjątki: silnik gry Unity używa C # *, a Minecraft używa Java, ale są one wyjątkiem, a nie regułą. Ogólnie,
* Nawet Unity to nie wszystko C #, ogromne części to C ++, a po prostu używasz C # do kodu gry.
EDYCJA Aby odpowiedzieć na niektóre komentarze, które pojawiły się po opublikowaniu tego: Być może zbytnio upraszczałem zbyt wiele, po prostu dawałem ogólny obraz. W przypadku programowania odpowiedź nigdy nie jest prosta. Istnieją interpretery dla C, JavaScript może działać poza przeglądarką, a C # może działać na prawie wszystkim dzięki Mono. Różne języki programowania są wyspecjalizowane dla różnych domen, ale jakiś programista prawdopodobnie wymyślił, jak uruchomić dowolny język w dowolnym kontekście. Ponieważ OP wydawał się nie znać dużo programowania (założenie z mojej strony, przepraszam, jeśli się mylę), starałem się zachować prostą odpowiedź.
Jeśli chodzi o komentarze o tym, że C # jest prawie tak szybki jak C ++, kluczowym słowem jest prawie. Kiedy byłem na studiach, zwiedziliśmy wiele firm z branży gier, a mój nauczyciel (który zachęcał nas do przejścia od C # do C ++ przez cały rok) pytał programistów z każdej firmy, w której poszliśmy, dlaczego C ++ zamiast C # i każda z nich powiedział C # jest zbyt wolny. Zasadniczo działa szybko, ale moduł wyrzucania elementów bezużytecznych może zaszkodzić wydajności, ponieważ nie można kontrolować, kiedy działa, i ma prawo cię zignorować, jeśli nie chce uruchamiać się zgodnie z zaleceniami. Jeśli potrzebujesz czegoś, co ma być wysoką wydajnością, nie chcesz czegoś tak nieprzewidywalnego.
Aby odpowiedzieć na mój komentarz „tylko osiągające prędkości”, tak, znaczna część wzrostu prędkości C # pochodzi z lepszego sprzętu, ale wraz z poprawą frameworka .NET i kompilatora C # nastąpiły pewne przyspieszenia.
W zależności od komentarza „gry są pisane w tym samym języku, co silnik”. Niektóre są, ale wiele z nich jest napisanych w języku hybrydowym. Unreal potrafi używać UnrealScript i C ++, Unity robi C # Javascript i Boo, wiele innych silników napisanych w C lub C ++ używa Pythona lub Lua jako języków skryptowych. Nie ma tam prostej odpowiedzi.
I tylko dlatego, że zmusił mnie do przeczytania „kogo to obchodzi, jeśli gra działa z prędkością 200 lub 120 klatek na sekundę”, jeśli gra działa szybciej niż 60 klatek na sekundę, prawdopodobnie marnujesz czas procesora, ponieważ przeciętny monitor nawet tego nie odświeża szybki. Niektóre wyższe i nowsze mają, ale nie jest to standard (jeszcze ...).
Jeśli chodzi o uwagę dotyczącą „ignorowania dziesięcioleci techniki”, wciąż mam 20 lat, więc kiedy ekstrapoluję wstecz, w większości powtarzam to, co powiedzieli mi starsi i bardziej doświadczeni programiści. Oczywiście będzie to kwestionowane na takiej stronie, ale warto to rozważyć.
źródło
To zabawne, że twierdzisz, że C nie jest bezpieczniejszy, ponieważ „ma wskaźniki”. Jest odwrotnie: Java i C # mają praktycznie tylko wskaźniki (dla typów innych niż rodzime). Najczęstszym błędem w Javie jest prawdopodobnie wyjątek Null Pointer (por. Https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). Drugim najczęściej występującym błędem jest prawdopodobnie przechowywanie ukrytych odniesień do nieużywanych obiektów (np. Zamknięte dialogi nie są usuwane), których w związku z tym nie można zwolnić, co prowadzi do długotrwałych programów z ciągle rosnącym stopniem pamięci.
Istnieją dwa podstawowe mechanizmy, które sprawiają, że C # i Java są bezpieczniejsze i bezpieczniejsze na dwa różne sposoby:
Najnowsze inteligentne wskaźniki C ++ ułatwiają programistom to zadanie.
Czas działania nie chroni przed np. Próbami przekroczenia bufora, ale teoretycznie nie pozwala na wykorzystanie takich programów. Natomiast w C i C ++ programista musi bezpiecznie kodować, aby zapobiec exploitom. Zwykle nie osiąga się tego od razu, ale wymaga przeglądu i iteracji.
Warto jednak zauważyć, że skomplikowany czas działania stanowi również zagrożenie dla bezpieczeństwa. Wydaje mi się, że Oracle aktualizuje JVM co kilka tygodni z powodu nowo wykrytych problemów z bezpieczeństwem. Oczywiście znacznie trudniej jest zweryfikować JVM niż pojedynczy program.
Bezpieczeństwo skomplikowanego czasu pracy jest zatem dwuznaczne i do pewnego stopnia mylące: Twój średni program C można, dzięki przeglądom i iteracjom, zapewnić względnie bezpiecznemu bezpieczeństwu. Twój przeciętny program Java jest tak bezpieczny, jak JVM; to znaczy nie do końca. Nigdy.
Artykuł na
gets()
ten temat zawiera linki do historycznych decyzji bibliotecznych, które zostałyby dzisiaj podjęte inaczej, a nie podstawowy język.źródło
Ponieważ „bezpieczeństwo” kosztuje prędkość, „bezpieczniejsze” języki działają wolniej.
Pytasz, dlaczego używasz „niebezpiecznego” języka, takiego jak C lub C ++, każesz komuś napisać ci sterownik wideo lub podobny w Pythonie lub Javie itp. I zobaczysz, co myślisz o „bezpieczeństwie” :)
Poważnie, musisz być tak blisko podstawowej pamięci maszyny, aby móc manipulować pikselami, rejestrami itp. ... Java lub Python nie mogą tego zrobić z żadną szybkością godną wydajności ... C i C ++ zarówno pozwalają to zrobić za pomocą wskaźników i tym podobnych ...
źródło
Oprócz wszystkich powyższych, istnieje również jeden dość powszechny przypadek użycia, który używa C jako wspólnej biblioteki dla innych języków.
Zasadniczo prawie wszystkie języki mają interfejs API do C.
Prosty przykład, spróbuj utworzyć wspólną aplikację dla Linux / IOS / Android / Windows. Oprócz wszystkich dostępnych narzędzi, skończyliśmy na zrobieniu biblioteki podstawowej w C, a następnie zmianie GUI dla każdego środowiska, czyli:
Moje dwa centy,
źródło
Podstawową trudnością związaną z C jest to, że nazwa jest używana do opisania wielu dialektów o identycznej składni, ale bardzo różnej semantyce. Niektóre dialekty są znacznie bezpieczniejsze niż inne.
W języku C, jak pierwotnie zaprojektował Dennis Ritchie, instrukcje C byłyby generalnie odwzorowane na instrukcje maszynowe w przewidywalny sposób. Ponieważ C mógł działać na procesorach, które zachowywały się inaczej, gdy wystąpiły takie rzeczy, jak podpisane przepełnienie arytmetyczne, programista, który nie wiedział, jak zachowa się maszyna w przypadku przepełnienia arytmetycznego, nie wiedziałby, jaki kod C działający na tym komputerze zachowałby się również, ale jeśli wiadomo, że komputer zachowuje się w określony sposób (np. owijanie komplementu dwóch cichych), wówczas implementacje na tej maszynie zwykle działałyby podobnie. Jednym z powodów, dla których C zyskał reputację szybkiego, było to, że w przypadkach, gdy programiści wiedzieli, że naturalne zachowanie platformy w scenariuszach skrajnych będzie odpowiadało ich potrzebom, nie było potrzeby, aby programista lub kompilator pisał kod w celu wygenerowania takich scenariuszy. .
Niestety twórcy kompilatorów przyjęli pogląd, że skoro standard nie nakłada żadnych wymagań na to, co implementacje muszą zrobić w takich przypadkach (luźność, która miała umożliwić implementacje sprzętowe, które mogą nie zachowywać się przewidywalnie), kompilatory powinny swobodnie generować kod, który neguje prawa czasu i przyczynowości.
Zastanów się nad czymś takim:
Hipernowoczesna (ale modna) teoria kompilatora sugerowałaby, że kompilator powinien wypisać „QUACK!” bezwarunkowo, ponieważ w każdym przypadku, gdy warunek był fałszywy, program w końcu wywołałby niezdefiniowane zachowanie wykonując wielokrotność, której wynik i tak zostanie zignorowany. Ponieważ Standard pozwoliłby kompilatorowi robić wszystko, co mu się podoba w takim przypadku, pozwala on kompilatorowi na wyjście „QUACK!”.
Podczas gdy C był bezpieczniejszy niż język asemblera, w hipernowoczesnych kompilatorach jest odwrotnie. W języku asemblera przepełnienie liczb całkowitych może spowodować, że obliczenia przyniosą bezsensowny wynik, ale na większości platform będzie to zakres jego efektów. Jeśli wyniki i tak zostaną zignorowane, przepełnienie nie będzie miało znaczenia. Jednak w hipernowoczesnym C nawet to, co normalnie byłoby „łagodnymi” formami niezdefiniowanego zachowania (takie jak przepełnienie liczby całkowitej w obliczeniach, które ostatecznie zostaje zignorowane) może spowodować wykonanie dowolnego programu.
źródło
int arr[5][[5]
, próba dostępuarr[0][5]
da nieokreślone zachowanie. Taka reguła umożliwia kompilatorowi, któremu podano coś w rodzajuarr[1][0]=3; arr[0][i]=6; arr[1][0]++;
wnioskowania, którearr[1][0]
będzie równe 4, bez względu na wartośći
.Przyczyny historyczne. Często nie piszę zupełnie nowego kodu, głównie utrzymuję i rozszerzam stare rzeczy, które działają od dziesięcioleci. Cieszę się, że to C, a nie Fortran.
Mogę się zirytować, gdy jakiś uczeń mówi: „Ale dlaczego, u licha, robisz to okropne X, skoro możesz robić Y?”. Cóż, X to praca, którą mam i bardzo ładnie płaci rachunki. Robiłem Y przy okazji i było fajnie, ale X jest tym, co większość z nas robi.
źródło
Co jest „niebezpieczne”?
Twierdzenie, że C jest „niebezpieczne”, jest częstym tematem wojen językowych o płomienie (najczęściej w porównaniu z Javą). Jednak dowody na to twierdzenie są niejasne.
C to język z określonym zestawem funkcji. Niektóre z tych funkcji mogą dopuszczać pewne rodzaje błędów, które nie są dozwolone przez inne typy języków (ryzyko zarządzania pamięcią C jest zwykle podkreślone). Nie jest to jednak to samo, co argument, że C jest bardziej niebezpieczny niż inne języki ogółem . Nie znam nikogo, kto dostarczy przekonujące dowody na ten temat.
Również „niebezpieczne” zależy od kontekstu: co próbujesz zrobić i jakie rodzaje obaw się martwisz?
W wielu kontekstach uważałbym C za „niebezpieczny” niż język wysokiego poziomu, ponieważ wymaga to większej ręcznej implementacji podstawowej funkcjonalności, zwiększając ryzyko błędów. Na przykład wykonanie podstawowego przetwarzania tekstu lub opracowanie strony internetowej w C byłoby zwykle głupie, ponieważ inne języki mają funkcje, które znacznie to ułatwiają.
Jednak C i C ++ są szeroko stosowane w systemach o znaczeniu krytycznym, ponieważ mniejszy język z bardziej bezpośrednią kontrolą hardward jest w tym kontekście uważany za „bezpieczniejszy”. Z bardzo dobrej odpowiedzi Przepełnienie stosu :
źródło
Aby dodać do istniejących odpowiedzi, dobrze jest powiedzieć, że wybierzesz Python lub PHP dla swojego projektu, ze względu na ich względne bezpieczeństwo. Ale ktoś musi wdrożyć te języki, a kiedy to zrobi, prawdopodobnie zrobi to w C. (Lub, no cóż, coś podobnego).
Dlatego ludzie używają C - do tworzenia mniej niebezpiecznych narzędzi, z których chcesz korzystać.
źródło
Pozwól, że przeredaguję twoje pytanie:
Niebezpiecznie można użyć dowolnego interesującego narzędzia, w tym języków programowania. Państwo dowiedzieć się więcej, dzięki czemu można zrobić więcej (i tak, że mniejsze niebezpieczeństwo jest tworzony podczas korzystania z narzędzia). W szczególności uczysz się tego narzędzia, dzięki czemu możesz robić rzeczy, do których narzędzie jest dobre (i być może rozpoznajesz, kiedy to narzędzie jest najlepszym narzędziem spośród narzędzi, które znasz).
Na przykład, jeśli chcesz umieścić cylindryczny otwór o średnicy 6 mm i głębokości 5 cm w bloku drewna, wiertło jest znacznie lepszym narzędziem niż parser LALR. Jeśli wiesz, jakie są te dwa narzędzia, wiesz, które z nich jest odpowiednie. Jeśli już wiesz, jak korzystać z wiertła, voila !, dziura.
C to tylko kolejne narzędzie. Jest lepszy do niektórych zadań niż do innych. Inne odpowiedzi tutaj rozwiązują ten problem. Jeśli nauczysz się trochę C, zrozumiesz, kiedy jest to właściwe narzędzie, a kiedy nie.
źródło
Nie ma konkretnego powodu, aby nie uczyć się C, ale sugerowałbym C ++. Oferuje wiele z tego, co robi C (ponieważ C ++ jest super zestawem C), z dużą ilością „dodatków”. Nauka języka C przed C ++ jest niepotrzebna - są to właściwie oddzielne języki.
Innymi słowy, gdyby C był zestawem narzędzi do obróbki drewna, prawdopodobnie byłby to:
Za pomocą tych narzędzi możesz zbudować wszystko - ale wszystko, co miłe, wymaga dużo czasu i umiejętności.
C ++ to kolekcja elektronarzędzi w lokalnym sklepie z narzędziami.
Jeśli zaczniesz korzystać z podstawowych funkcji językowych, C ++ ma stosunkowo niewielką dodatkową krzywą uczenia się.
Ponieważ niektórzy ludzie nie chcą mebli od IKEA. =)
Poważnie, chociaż w wielu językach, które są „wyższe” niż C lub C ++, mogą występować elementy, które czynią je (potencjalnie) „łatwiejszymi” w niektórych aspektach, nie zawsze jest to dobra rzecz. Jeśli nie podoba ci się sposób, w jaki coś się robi lub funkcja nie jest zapewniona, prawdopodobnie niewiele możesz z tym zrobić. Z drugiej strony C i C ++ zapewniają wystarczająco dużo funkcji języka „niskiego poziomu” (w tym wskaźników), aby można było uzyskać dostęp do wielu rzeczy bezpośrednio (szczególnie sprzętowo lub pod względem systemu operacyjnego) lub zbudować je samodzielnie, co może nie być możliwe w innych języki jak zaimplementowane.
Mówiąc dokładniej, C ma następujący zestaw funkcji, które sprawiają, że jest pożądany dla wielu programistów:
Kompatybilność - C istnieje już od dawna i każdy ma do tego narzędzia i biblioteki. Sam język również nie jest wybredny - oczekuje, że procesor wykona instrukcje, a pamięć zapisze rzeczy i tyle.
Ponadto istnieje coś takiego jak Application Binary Interface (ABI) . Krótko mówiąc, jest to sposób komunikowania się programów na poziomie kodu maszynowego, który może mieć zalety w stosunku do interfejsu programowania aplikacji (API) . Podczas gdy inne języki, takie jak C ++, mogą mieć ABI, zazwyczaj są one mniej jednolite (uzgodnione) niż C, więc C stanowi dobry język podstawowy, gdy z jakiegoś powodu chcesz użyć ABI do komunikacji z innym programem.
Wydajność (i czasami schematy zarządzania pamięcią, których nie można wdrożyć bez względnie bezpośredniego dostępu do pamięci).
Bezpośredni dostęp do pamięci za pomocą wskaźników wprowadza wiele schludnych (zwykle szybkich) sztuczek, kiedy możesz umieścić swoje brudne łapy na małych i zerach w twoich komórkach pamięci bezpośrednio i nie musisz czekać, aż ten wredny nauczyciel wręcza zabawki po prostu w czasie zabawy, a następnie ponownie je zgarnij.
Krótko mówiąc, dodawanie rzeczy potencjalnie powoduje opóźnienie lub w inny sposób wprowadza niepożądaną złożoność.
Jeśli chodzi o języki skryptowe i podobne, musisz ciężko pracować, aby języki wymagające programów pomocniczych działały tak skutecznie, jak natywnie C (lub dowolny skompilowany język). Dodanie tłumacza w locie z natury wprowadza możliwość zmniejszenia prędkości wykonywania i zwiększenia zużycia pamięci, ponieważ dodajesz inny program do miksu. Wydajność programów zależy w równym stopniu od wydajności tego dodatkowego programu, jak również od tego, jak dobrze (źle =)) napisałeś oryginalny kod programu. Nie wspominając o tym, że twój program jest często całkowicie zależny od drugiego programu, aby nawet go uruchomić. Ten drugi program z jakiegoś powodu nie istnieje w danym systemie? Kod nie idź.
W rzeczywistości wprowadzenie czegoś „dodatkowego” potencjalnie spowalnia lub komplikuje kod. W językach „bez przerażających wskaźników” zawsze czekasz na inne fragmenty kodu, które wyczyszczą się za tobą lub w inny sposób wymyślisz „bezpieczne” sposoby wykonywania różnych czynności - ponieważ Twój program nadal wykonuje te same operacje dostępu do pamięci, jakie można wykonać za pomocą wskaźniki Po prostu nie jesteś tym, który się tym zajmuje (więc nie możesz tego pieprzyć, geniusz = P).
Zgodnie z przyjętą odpowiedzią:
Myśl, że ponieważ coś można zrobić w języku, musi być zrobione, jest głupie. Języki mają wady, które można naprawić. Ze względu na kompatybilność ze starszym kodem ta konstrukcja może być nadal używana. Ale nic (prawdopodobnie) nie zmusza programisty do użycia get (), a tak naprawdę to polecenie zostało zasadniczo zastąpione bezpieczniejszymi alternatywami.
Co więcej, problem z get () nie jest sam w sobie problemem ze wskaźnikiem . Jest to problem z poleceniem, które niekoniecznie wie, jak bezpiecznie korzystać z pamięci. W sensie abstrakcyjnym są to wszystkie problemy ze wskaźnikami - czytanie i pisanie rzeczy, których nie powinieneś. To nie jest problem ze wskaźnikami; jest to problem z implementacją wskaźnika.
Aby wyjaśnić, wskaźniki nie są niebezpieczne, dopóki przypadkowo nie uzyskasz dostępu do miejsca w pamięci, do którego nie miałeś zamiaru. I nawet wtedy nie gwarantuje to, że komputer się stopi lub wybuchnie. W większości przypadków twój program po prostu przestanie działać (poprawnie).
To powiedziawszy, ponieważ ponieważ wskaźniki zapewniają dostęp do lokalizacji w pamięci oraz ponieważ dane i kod wykonywalny istnieją razem w pamięci, istnieje realne niebezpieczeństwo przypadkowego uszkodzenia, aby można było właściwie zarządzać pamięcią.
Do tego momentu, ponieważ prawdziwie bezpośrednie operacje dostępu do pamięci często przynoszą ogólnie mniej korzyści, niż mogły to być lata temu, nawet języki nieskradzione, takie jak C ++, wprowadziły takie elementy, jak inteligentne wskaźniki, które pomagają wypełnić lukę między wydajnością pamięci a bezpieczeństwem.
Podsumowując, nie ma powodu, aby obawiać się wskaźnika, o ile jest on bezpiecznie używany. Wystarczy skorzystać z podpowiedzi z wersji Steve'a „The Crocodile Hunter” Irwina z South Park - nie chowaj kciuka w otworach krokodyli .
źródło
Jak zawsze język programowania jest jedynie konsekwencją rozwiązywania problemów. Powinieneś nauczyć się nie tylko języka C, ale wielu różnych języków (i innych sposobów programowania komputera, czy to narzędzi GUI, czy interpreterów poleceń), aby mieć przyzwoity zestaw narzędzi do rozwiązywania problemów.
Czasami okaże się, że problem dobrze pasuje do czegoś, co jest zawarte w domyślnych bibliotekach Java, w takim przypadku możesz wybrać Javę, aby to wykorzystać. W innych przypadkach może być konieczne zrobienie czegoś w systemie Windows, co jest dużo prostsze w środowisku uruchomieniowym .NET, więc możesz użyć C # lub VB. Może istnieć narzędzie graficzne lub skrypt poleceń, który rozwiązuje twój problem, wtedy możesz ich użyć. Być może musisz napisać aplikację GUI na wielu platformach, Java może być opcją, biorąc pod uwagę biblioteki zawarte w JDK, ale z drugiej strony jedna platforma docelowa może nie mieć JRE, więc może zamiast tego wybierzesz C i SDL (lub podobne).
C ma ważną pozycję w tym zestawie narzędzi, ponieważ jest ogólny, mały i szybki, a także kompiluje się do kodu maszynowego. Obsługiwany jest również na każdej platformie pod słońcem (jednak nie bez ponownej kompilacji).
Podsumowując, powinieneś nauczyć się jak największej liczby narzędzi, języków i paradygmatów.
Proszę oderwać się od sposobu myślenia: „Jestem programistą X” (X = C, C ++, Java itp.)
Wystarczy użyć „Jestem programistą”.
Programista rozwiązuje problemy i projektuje algorytmy, instruując maszyny, aby wykonały obciążenie pracą. Koniec opowieści. Nie ma to znaczenia dla języka. Najważniejszą umiejętnością jest rozwiązywanie problemów i logiczne rozkładanie problemów strukturalnych, umiejętność / wybór języka ZAWSZE jest drugorzędny i / lub jest konsekwencją charakteru problemu.
Interesującą ścieżką, jeśli interesuje Cię C, jest rozszerzenie zestawu umiejętności o Go. Go jest naprawdę ulepszonym C, z odśmiecaniem i interfejsami, a także ładnym wbudowanym modelem / kanałami wątków, które również przynoszą wiele korzyści C (takich jak arytmetyka wskaźników i kompilacja do kodu maszynowego).
źródło
To zależy od tego, co zamierzasz z tym zrobić. C został zaprojektowany jako zamiennik języka asemblera i jest językiem wysokiego poziomu, który jest najbliższy językowi maszynowemu. W związku z tym ma niskie koszty ogólne i wydajność i nadaje się do programowania systemów i innych zadań, które wymagają niewielkiej powierzchni i zbliżania się do podstawowego sprzętu.
źródło
Kiedy pracujesz na poziomie bitów i bajtów, pamięci jako surowego jednorodnego zbioru danych, co często byłoby wymagane do skutecznego wdrożenia najbardziej wydajnych alokatorów i struktur danych, nie ma bezpieczeństwa. Bezpieczeństwo to przede wszystkim silna koncepcja związana z typem danych, a alokator pamięci nie działa z typami danych. Działa z bitami i bajtami, aby połączyć je z tymi samymi bitami i bajtami potencjalnie reprezentującymi jeden typ danych w danym momencie i innym później.
W tym przypadku nie ma znaczenia, czy użyjesz C ++. Nadal będziesz krążył
static_casts
po całym kodzie, aby rzucać zevoid*
wskaźników, nadal pracując z bitami i bajtami i po prostu radząc sobie z większymi problemami związanymi z przestrzeganiem systemu typów w tym kontekście niż C, który ma znacznie prostszy system typów, w którym jesteś wolny domemcpy
bitów i bajtów, nie martwiąc się o buldożerowanie nad systemem typów.W rzeczywistości często trudniej jest pracować w C ++, ogólnie bezpieczniejszym języku, w tak niskim kontekście bitów i bajtów bez pisania nawet bardziej niebezpiecznego kodu niż w C, ponieważ możesz buldożować się nad systemem typów C ++ i robić rzeczy takie jak nadpisywanie vptrs i nie wywoływanie konstruktorów kopiowania i destruktorów w odpowiednim czasie. Jeśli poświęcisz odpowiedni czas, aby uszanować te typy i zastosujesz nowe i ręcznie przywołujesz lekarzy, i tak dalej, będziesz narażony na świat obsługi wyjątków w kontekście zbyt niskim, aby RAII był praktyczny, i osiągnięcie wyjątku - bezpieczeństwo w kontekście niskiego poziomu jest bardzo trudne (musisz udawać, że prawie każda funkcja może rzucić i złapać wszystkie możliwości i wycofać wszelkie efekty uboczne jako niepodzielna transakcja, jakby nic się nie wydarzyło). Kod C często „
Niemożliwe byłoby wdrożenie takich alokatorów w językach, które nie pozwolą ci stać się „niebezpiecznym” tutaj; będziesz musiał polegać na wszystkich udostępnianych przez siebie alokatorach (najprawdopodobniej zaimplementowanych w C lub C ++) i mieć nadzieję, że będzie wystarczająco dobry dla twoich celów. I prawie zawsze istnieją bardziej wydajne, ale mniej ogólne alokatory i struktury danych odpowiednie do konkretnych celów, ale o wiele bardziej wąskie, ponieważ są one specjalnie dostosowane do twoich celów.
Większość ludzi nie potrzebuje takich jak C lub C ++, ponieważ mogą po prostu wywołać kod pierwotnie zaimplementowany w C lub C ++ lub ewentualnie nawet zaimplementowany już dla nich zestaw. Wielu może odnieść korzyści z innowacji na wysokim poziomie, takich jak łączenie ze sobą programu graficznego, który po prostu wykorzystuje biblioteki istniejących funkcji przetwarzania obrazu już zaimplementowanych w C, gdzie nie wprowadzają tak dużych innowacji na najniższym poziomie zapętlania poszczególnych pikseli, ale może oferując bardzo przyjazny interfejs użytkownika i przepływ pracy, jakiego nigdy wcześniej nie widziano. W takim przypadku, jeśli celem oprogramowania jest po prostu wywoływanie wywołań wysokiego poziomu w bibliotekach niskiego poziomu ( „przetwarzaj dla mnie cały obraz, a nie dla każdego piksela, zrób coś” ), może to być prawdopodobnie przedwczesna optymalizacja nawet próby rozpoczęcia pisania takiej aplikacji w C.
Ale jeśli robisz coś nowego na niskim poziomie, gdzie pomaga on uzyskać dostęp do danych w sposób niskopoziomowy, jak zupełnie nowy filtr obrazu, którego nigdy wcześniej nie widziałem, który jest wystarczająco szybki, aby pracować na wideo HD w czasie rzeczywistym, zazwyczaj musisz uzyskać trochę niebezpieczne.
Łatwo jest uznać to za coś oczywistego. Pamiętam post na Facebooku, w którym ktoś wskazał, jak możliwe jest stworzenie gry wideo w języku Python z sugestią, że języki niskiego poziomu stają się przestarzałe, a na pewno była to gra przyzwoicie wyglądająca. Ale Python robił wywołania wysokiego poziomu do bibliotek zaimplementowanych w C, aby wykonać całą ciężką pracę. Nie możesz tworzyć Unreal Engine 4, po prostu wykonując wywołania wysokiego poziomu w istniejących bibliotekach. Unreal Engine 4 jestBiblioteka. Robił wiele rzeczy, które nigdy nie istniały w innych bibliotekach i silnikach, od oświetlenia po nawet system węzłów, i jak mógł kompilować i uruchamiać kod w locie. Jeśli chcesz wprowadzać innowacje na niskim poziomie silnika / rdzenia / jądra, musisz uzyskać niski poziom. Gdyby wszyscy twórcy gier zmienili się na bezpieczne języki wysokiego poziomu, nie byłoby Unreal Engine 5, 6 lub 7. Prawdopodobnie ludzie nadal używaliby Unreal Engine 4 dekady później, ponieważ nie można wprowadzać innowacji na poziomie wymaganym do przyjścia dzięki silnikowi nowej generacji, wykonując połączenia na wysokim poziomie w starym.
źródło