Προγραμματισμός

Γιατί εξακολουθεί να ισχύει η γλώσσα προγραμματισμού C

Καμία τεχνολογία δεν παραμένει για 50 χρόνια, εκτός αν κάνει τη δουλειά της καλύτερη από οτιδήποτε άλλο - ειδικά μια τεχνολογία υπολογιστών. Η γλώσσα προγραμματισμού C είναι ζωντανή και ξεκινά από το 1972 και εξακολουθεί να βασίζεται ως ένα από τα θεμελιώδη δομικά στοιχεία του κόσμου που καθορίζεται από λογισμικό.

Αλλά μερικές φορές μια τεχνολογία παραμένει επειδή οι άνθρωποι δεν έχουν φτάσει να την αντικαταστήσουν. Τις τελευταίες δεκαετίες, δεκάδες άλλες γλώσσες εμφανίστηκαν - ορισμένες έχουν σχεδιαστεί ρητά για να αμφισβητήσουν την κυριαρχία του Γ, κάποιες απομακρύνουν το C από την πλευρά ως υποπροϊόν της δημοτικότητάς τους.

Δεν είναι δύσκολο να υποστηρίξουμε ότι το C χρειάζεται αντικατάσταση. Ο προγραμματισμός γλωσσικών ερευνών και πρακτικών ανάπτυξης λογισμικού υποδηλώνει πώς υπάρχουν πολύ καλύτεροι τρόποι για να κάνουμε πράγματα από ό, τι για τον Γ. Όμως ο C παραμένει το ίδιο, με δεκαετίες έρευνας και ανάπτυξης πίσω από αυτό. Λίγες άλλες γλώσσες μπορούν να το κερδίσουν για απόδοση, για συμβατότητα με γυμνά μέταλλα ή για πανταχού παρούσα. Ακόμα, αξίζει να δούμε πώς το C αντιμετωπίζει τον διαγωνισμό γλωσσών μεγάλων ονομάτων το 2018.

C εναντίον C ++

Φυσικά, το C συγκρίνεται πιο συχνά με το C ++, η γλώσσα που - όπως υποδηλώνει το ίδιο το όνομα - δημιουργήθηκε ως επέκταση του C. Οι διαφορές μεταξύ C ++ και C θα μπορούσαν να χαρακτηριστούν ως εκτεταμένες, ήυπερβολικό, ανάλογα με το ποιον ρωτάτε.

Ενώ εξακολουθεί να μοιάζει με C στη σύνταξη και την προσέγγισή του, το C ++ παρέχει πολλές πραγματικά χρήσιμες λειτουργίες που δεν διατίθενται εγγενώς στο C: χώρους ονομάτων, πρότυπα, εξαιρέσεις, αυτόματη διαχείριση μνήμης και ούτω καθεξής. Έργα που απαιτούν κορυφαία απόδοση - βάσεις δεδομένων, συστήματα μηχανικής μάθησης - γράφονται συχνά σε C ++ χρησιμοποιώντας αυτές τις δυνατότητες για να απομακρύνουν κάθε πτώση απόδοσης από το σύστημα.

Επιπλέον, το C ++ συνεχίζει να επεκτείνεται πολύ πιο επιθετικά από το C. Το επερχόμενο C ++ 20 φέρνει ακόμη περισσότερα στο τραπέζι συμπεριλαμβανομένων των ενοτήτων, των κορουτίνων, μιας βιβλιοθήκης συγχρονισμού και εννοιών, που καθιστούν τα πρότυπα ευκολότερα στη χρήση. Η τελευταία αναθεώρηση στο πρότυπο C προσθέτει λίγα και εστιάζει στη διατήρηση της συμβατότητας προς τα πίσω.

Αυτό είναι, όλα τα πλεονεκτήματα στο C ++ μπορούν επίσης να λειτουργήσουν ως μείον. Μεγάλα. Όσο περισσότερες δυνατότητες C ++ χρησιμοποιείτε, τόσο μεγαλύτερη πολυπλοκότητα εισάγετε και τόσο πιο δύσκολο γίνεται να εξημερώσετε τα αποτελέσματα. Οι προγραμματιστές που περιορίζονται σε ένα υποσύνολο του C ++ μπορούν να αποφύγουν πολλές από τις χειρότερες παγίδες και υπερβολές. Ωστόσο, ορισμένα καταστήματα θέλουν να προστατεύσουν από την πολυπλοκότητα του C ++. Η προσκόλληση με το C αναγκάζει τους προγραμματιστές να περιοριστούν σε αυτό το υποσύνολο. Η ομάδα ανάπτυξης του πυρήνα Linux, για παράδειγμα, αποφεύγει το C ++.

Η επιλογή του C πέρα ​​από το C ++ είναι ένας τρόπος για εσάς - και για τυχόν προγραμματιστές που διατηρούν τον κώδικα μετά από εσάς - να αποφύγετε να μπλέξετε με τις υπερβολές C ++, αγκαλιάζοντας έναν επιβλητικό μινιμαλισμό. Φυσικά, το C ++ διαθέτει ένα πλούσιο σύνολο χαρακτηριστικών υψηλού επιπέδου για καλό λόγο. Αλλά αν ο μινιμαλισμός ταιριάζει καλύτερα σε τρέχοντα και μελλοντικά έργα - και σε έργα της ομάδας- τότε το C έχει πιο νόημα.

C εναντίον Java

Μετά από δεκαετίες, η Java παραμένει βασική ανάπτυξη εταιρικού λογισμικού - και γενικά βασική ανάπτυξη. Πολλά από τα πιο σημαντικά έργα εταιρικού λογισμικού γράφτηκαν στην Java - συμπεριλαμβανομένης της συντριπτικής πλειοψηφίας των έργων Apache Software Foundation - και η Java παραμένει μια βιώσιμη γλώσσα για την ανάπτυξη νέων έργων με απαιτήσεις εταιρικού επιπέδου.

Η σύνταξη Java δανείζεται πολλά από τα C και C ++. Σε αντίθεση με το C, ωστόσο, η Java δεν συντάσσει από προεπιλογή τον εγγενή κώδικα. Αντ 'αυτού, το περιβάλλον εκτέλεσης Java, το JVM, JIT (just-in-time) μεταγλωττίζει τον κώδικα Java για εκτέλεση στο περιβάλλον προορισμού. Υπό τις σωστές συνθήκες, ο κώδικας JITted Java μπορεί να προσεγγίσει ή ακόμη και να υπερβεί την απόδοση του C.

Η φιλοσοφία «γράψτε μία φορά, τρέξτε οπουδήποτε» πίσω από την Java επιτρέπει επίσης την εκτέλεση προγραμμάτων Java με σχετικά μικρή προσαρμογή για μια αρχιτεκτονική στόχου. Αντίθετα, παρόλο που το C έχει μεταφερθεί σε πάρα πολλές αρχιτεκτονικές, οποιοδήποτε δεδομένο πρόγραμμα C μπορεί να εξακολουθεί να χρειάζεται προσαρμογή για να λειτουργεί σωστά, ας πούμε, Windows έναντι Linux.

Αυτός ο συνδυασμός φορητότητας και ισχυρής απόδοσης, σε συνδυασμό με ένα τεράστιο οικοσύστημα βιβλιοθηκών και πλαισίων λογισμικού, καθιστούν την Java μια γλώσσα και χρόνο εκτέλεσης για την κατασκευή επιχειρηματικών εφαρμογών.

Όπου η Java υπολείπεται του C είναι μια περιοχή όπου η Java δεν προοριζόταν ποτέ να ανταγωνιστεί: τρέξιμο κοντά στο μέταλλο ή εργασία απευθείας με υλικό. Ο κωδικός C μεταγλωττίζεται σε κώδικα μηχανήματος, ο οποίος εκτελείται απευθείας από τη διαδικασία. Η Java μεταγλωττίζεται σε bytecode, ο οποίος είναι ενδιάμεσος κώδικας που ο διερμηνέας JVM μετατρέπει στη συνέχεια σε κώδικα μηχανήματος. Επιπλέον, αν και η αυτόματη διαχείριση μνήμης της Java είναι μια ευλογία στις περισσότερες περιπτώσεις, το C είναι πιο κατάλληλο για προγράμματα που πρέπει να κάνουν βέλτιστη χρήση περιορισμένων πόρων μνήμης.

Τούτου λεχθέντος, υπάρχουν ορισμένες περιοχές όπου η Java μπορεί να έρθει κοντά στο C όσον αφορά την ταχύτητα. Ο κινητήρας JIT του JVM βελτιστοποιεί τις ρουτίνες κατά το χρόνο εκτέλεσης με βάση τη συμπεριφορά του προγράμματος, επιτρέποντας πολλές κατηγορίες βελτιστοποίησης που δεν είναι δυνατές με τη σύνταξη C. εκ των προτέρων. Για παράδειγμα, το Apache Spark βελτιστοποιεί εν μέρει την επεξεργασία στη μνήμη χρησιμοποιώντας προσαρμοσμένο κώδικα διαχείρισης μνήμης που παρακάμπτει το JVM.

C εναντίον C # και .Net

Σχεδόν δύο δεκαετίες μετά την εισαγωγή τους, το C # και το .Net Framework παραμένουν κύρια μέρη του επιχειρηματικού κόσμου. Έχει ειπωθεί ότι τα C # και .Net ήταν η απάντηση της Microsoft στην Java - ένα διαχειριζόμενο σύστημα μεταγλώττισης κώδικα και καθολικός χρόνος εκτέλεσης - και τόσες πολλές συγκρίσεις μεταξύ C και Java διατηρούν επίσης τα C και C # /. Net.

Όπως η Java (και σε κάποιο βαθμό η Python), το .Net προσφέρει φορητότητα σε διάφορες πλατφόρμες και ένα τεράστιο οικοσύστημα ολοκληρωμένου λογισμικού. Αυτά δεν είναι μικρά πλεονεκτήματα, δεδομένου του πόσο η επιχειρηματική ανάπτυξη λαμβάνει χώρα στον κόσμο .Net. Όταν αναπτύσσετε ένα πρόγραμμα σε C # ή σε οποιαδήποτε άλλη γλώσσα .Net, μπορείτε να σχεδιάσετε ένα σύμπαν εργαλείων και βιβλιοθηκών που έχουν γραφτεί για το .Net runtime.

Ένα άλλο πλεονέκτημα τύπου Java .NET είναι η βελτιστοποίηση JIT. Τα προγράμματα C # και .Net μπορούν να καταρτιστούν εκ των προτέρων σύμφωνα με το C, αλλά συντάσσονται κυρίως just-in-time από το .Net runtime και βελτιστοποιούνται με πληροφορίες χρόνου εκτέλεσης. Η συλλογή JIT επιτρέπει κάθε είδους επιτόπιες βελτιστοποιήσεις για ένα τρέχον. Καθαρό πρόγραμμα που δεν μπορεί να εκτελεστεί σε C.

Όπως τα C, C # και .Net παρέχουν διάφορους μηχανισμούς για άμεση πρόσβαση στη μνήμη. Ο σωρός, η στοίβα και η μη διαχειριζόμενη μνήμη συστήματος είναι προσβάσιμα μέσω .Net APIs και αντικειμένων. Και οι προγραμματιστές μπορούν να χρησιμοποιήσουν το επισφαλής λειτουργία σε .Net για επίτευξη ακόμη μεγαλύτερης απόδοσης.

Ωστόσο, κανένα από αυτά δεν παρέχεται δωρεάν. Διαχειριζόμενα αντικείμενα και επισφαλής τα αντικείμενα δεν μπορούν να ανταλλάσσονται αυθαίρετα και η διαλογή μεταξύ τους συνεπάγεται κόστος απόδοσης. Επομένως, η μεγιστοποίηση της απόδοσης των εφαρμογών .Net σημαίνει τη διατήρηση της κίνησης μεταξύ διαχειριζόμενων και μη διαχειριζόμενων αντικειμένων στο ελάχιστο.

Όταν δεν μπορείτε να πληρώσετε το πρόστιμο για διαχειριζόμενη έναντι μη διαχειριζόμενης μνήμης ή όταν ο καθαρός χρόνος εκτέλεσης είναι μια κακή επιλογή για το περιβάλλον προορισμού (π.χ. χώρος στον πυρήνα) ή μπορεί να μην είναι καθόλου διαθέσιμος, τότε το C είναι αυτό που εσείς χρειάζομαι. Και σε αντίθεση με τα C # και .Net, το C ξεκλειδώνει την άμεση πρόσβαση στη μνήμη από προεπιλογή.

C εναντίον Go

Η σύνταξη Go οφείλει πολλά σε C - σγουρά τιράντες ως οριοθέτες, δηλώσεις που τερματίζονται με ερωτηματικά και ούτω καθεξής. Οι προγραμματιστές με γνώσεις C μπορούν τυπικά να μεταπηδήσουν απευθείας στο Go χωρίς μεγάλη δυσκολία, ακόμη και λαμβάνοντας υπόψη νέες δυνατότητες Go, όπως χώρους ονομάτων και διαχείριση πακέτων.

Ο αναγνώσιμος κώδικας ήταν ένας από τους καθοδηγητικούς σχεδιαστικούς στόχους της Go: Διευκολύνετε τους προγραμματιστές να φτάσουν στην ταχύτητα με οποιοδήποτε έργο Go και να αποκτήσουν γνώσεις με τη βάση κώδικα σε σύντομη σειρά. Οι βάσεις κώδικα C μπορεί να είναι δύσκολο να χτυπηθούν, καθώς είναι επιρρεπείς να μετατραπούν σε μακροεντολή φωλιά αρουραίου και #ifdefείναι συγκεκριμένο τόσο για ένα έργο όσο και για μια δεδομένη ομάδα. Η σύνταξη του Go, και τα ενσωματωμένα εργαλεία μορφοποίησης κώδικα και διαχείρισης έργων, αποσκοπούν στην αποφυγή τέτοιων θεσμικών προβλημάτων.

Η Go διαθέτει επίσης πρόσθετα, όπως γορουτίνες και κανάλια, εργαλεία σε επίπεδο γλώσσας για τον χειρισμό ταυτόχρονων και μετάδοσης μηνυμάτων μεταξύ των στοιχείων. Η C θα απαιτούσε τέτοια πράγματα να τυλίγονται στο χέρι ή να παρέχονται από μια εξωτερική βιβλιοθήκη, αλλά η Go τα παρέχει απευθείας από το κουτί, καθιστώντας πολύ πιο εύκολο να κατασκευάσει λογισμικό που τα χρειάζεται.

Όπου το Go διαφέρει περισσότερο από το C κάτω από την κουκούλα είναι στη διαχείριση μνήμης. Τα αντικείμενα Go διαχειρίζονται αυτόματα και συλλέγονται σκουπίδια από προεπιλογή. Για τις περισσότερες εργασίες προγραμματισμού, αυτό είναι εξαιρετικά βολικό. Αλλά σημαίνει επίσης ότι οποιοδήποτε πρόγραμμα που απαιτεί ντετερμινιστικό χειρισμό μνήμης θα είναι πιο δύσκολο να γραφτεί.

Το Go περιλαμβάνει το επισφαλής πακέτο για την παράκαμψη ορισμένων από τις ασφάλειες χειρισμού τύπου Go, όπως ανάγνωση και εγγραφή αυθαίρετης μνήμης με ένα Δείκτης τύπος. Αλλά επισφαλής συνοδεύεται από μια προειδοποίηση ότι τα προγράμματα που γράφονται μαζί του "ενδέχεται να μην είναι φορητά και δεν προστατεύονται από τις οδηγίες συμβατότητας Go 1".

Το Go είναι κατάλληλο για τη δημιουργία προγραμμάτων, όπως βοηθητικά προγράμματα γραμμής εντολών και υπηρεσίες δικτύου, επειδή σπάνια χρειάζονται τόσο λεπτούς χειρισμούς. Όμως, προγράμματα οδήγησης συσκευών χαμηλού επιπέδου, στοιχεία λειτουργικού συστήματος πυρήνα-χώρου και άλλες εργασίες που απαιτούν ακριβή έλεγχο της διάταξης και της διαχείρισης της μνήμης δημιουργούνται καλύτερα στο C.

C εναντίον Rust

Με κάποιους τρόπους, το Rust είναι μια απάντηση στα αινίγματα διαχείρισης μνήμης που δημιουργήθηκαν από τους C και C ++, καθώς και σε πολλές άλλες αδυναμίες αυτών των γλωσσών επίσης. Το Rust μεταγλωττίζεται με τον εγγενή κώδικα του μηχανήματος, οπότε θεωρείται ισοδύναμο με το C ως προς την απόδοση. Η ασφάλεια της μνήμης από προεπιλογή, ωστόσο, είναι το κύριο σημείο πώλησης της Rust.

Οι κανόνες σύνταξης και σύνταξης του Rust βοηθούν τους προγραμματιστές να αποφύγουν τα κοινά σφάλματα διαχείρισης μνήμης. Εάν ένα πρόγραμμα έχει πρόβλημα διαχείρισης μνήμης που υπερβαίνει τη σύνταξη Rust, απλά δεν θα μεταγλωττιστεί. Οι νεοεισερχόμενοι στη γλώσσα, ειδικά από μια γλώσσα όπως η C που παρέχει άφθονο χώρο για τέτοια σφάλματα, περνούν την πρώτη φάση της εκπαίδευσης Rust μαθαίνοντας πώς να καθησυχάσουν τον μεταγλωττιστή. Ωστόσο, οι υποστηρικτές του Rust υποστηρίζουν ότι αυτός ο βραχυπρόθεσμος πόνος έχει μακροπρόθεσμη απόδοση: ασφαλέστερος κώδικας που δεν θυσιάζει την ταχύτητα.

Η σκουριά βελτιώνεται επίσης στο C με τα εργαλεία της. Η διαχείριση έργων και στοιχείων είναι μέρος της αλυσίδας εργαλείων που παρέχεται από προεπιλογή με το Rust, όπως και με το Go. Υπάρχει ένας προεπιλεγμένος, συνιστώμενος τρόπος για τη διαχείριση πακέτων, την οργάνωση φακέλων έργου και τον χειρισμό πολλών άλλων πραγμάτων που στην C είναι στην καλύτερη περίπτωση ad-hoc, με κάθε έργο και ομάδα να τα χειρίζεται διαφορετικά.

Ωστόσο, αυτό που θεωρείται πλεονέκτημα στο Rust μπορεί να μην μοιάζει με ένα προγραμματιστή C. Οι δυνατότητες ασφαλείας του Rust δεν μπορούν να απενεργοποιηθούν, επομένως ακόμη και το πιο ασήμαντο πρόγραμμα Rust πρέπει να συμμορφώνεται με τις αυστηρές προδιαγραφές ασφαλείας της Rust. Το C μπορεί να είναι λιγότερο ασφαλές από προεπιλογή, αλλά είναι πολύ πιο ευέλικτο και συγχωρεί όταν είναι απαραίτητο.

Ένα άλλο πιθανό μειονέκτημα είναι το μέγεθος της γλώσσας Rust. Το C έχει σχετικά λίγα χαρακτηριστικά, ακόμη και όταν λαμβάνεται υπόψη η τυπική βιβλιοθήκη. Το σετ χαρακτηριστικών Rust είναι εκτεταμένο και συνεχίζει να αναπτύσσεται. Όπως με το C ++, το μεγαλύτερο σετ χαρακτηριστικών Rust σημαίνει περισσότερη ισχύ, αλλά και μεγαλύτερη πολυπλοκότητα. Το C είναι μια μικρότερη γλώσσα, αλλά είναι πολύ πιο εύκολο να διαμορφωθεί διανοητικά, οπότε ίσως ταιριάζει καλύτερα σε έργα όπου το Rust θα ήταν υπερβολικό.

C εναντίον Python

Αυτές τις μέρες, όποτε η συζήτηση αφορά την ανάπτυξη λογισμικού, η Python φαίνεται πάντα να μπαίνει στη συζήτηση. Σε τελική ανάλυση, η Python είναι η «δεύτερη καλύτερη γλώσσα για τα πάντα» και αναμφίβολα μία από τις πιο ευέλικτες, με χιλιάδες βιβλιοθήκες τρίτων.

Αυτό που υπογραμμίζει η Python, και όπου διαφέρει περισσότερο από το C, ευνοεί την ταχύτητα ανάπτυξης σε σχέση με την ταχύτητα εκτέλεσης. Ένα πρόγραμμα που μπορεί να διαρκέσει μια ώρα για να συγκεντρωθεί σε μια άλλη γλώσσα - όπως το C - μπορεί να συναρμολογηθεί στην Python σε λίγα λεπτά. Από την άλλη πλευρά, αυτό το πρόγραμμα μπορεί να διαρκέσει δευτερόλεπτα για να εκτελεστεί σε C, αλλά ένα λεπτό για να τρέξει στην Python. (Ένας καλός κανόνας: Τα προγράμματα Python εκτελούν γενικά μια τάξη μεγέθους πιο αργή από τα αντίστοιχα C.) Αλλά για πολλές εργασίες σε σύγχρονο υλικό, το Python είναι αρκετά γρήγορο και αυτό ήταν το κλειδί για την πρόσληψή του.

Μια άλλη σημαντική διαφορά είναι η διαχείριση μνήμης. Τα προγράμματα Python διαχειρίζονται πλήρως τη μνήμη από τον χρόνο εκτέλεσης του Python, οπότε οι προγραμματιστές δεν χρειάζεται να ανησυχούν για τη χαριτωμένη κατανομή και απελευθέρωση μνήμης. Αλλά εδώ και πάλι, η ευκολία του προγραμματιστή έρχεται στο κόστος της απόδοσης χρόνου εκτέλεσης. Το γράψιμο προγραμμάτων C απαιτεί προσεκτική προσοχή στη διαχείριση της μνήμης, αλλά τα προκύπτοντα προγράμματα είναι συχνά το χρυσό πρότυπο για καθαρή ταχύτητα του μηχανήματος.

Κάτω από το δέρμα, ωστόσο, οι Python και C μοιράζονται μια βαθιά σύνδεση: ο χρόνος εκτέλεσης Python είναι γραμμένος σε C. Αυτό επιτρέπει στα προγράμματα Python να τυλίγουν βιβλιοθήκες γραμμένες σε C και C ++. Σημαντικά κομμάτια του οικοσυστήματος Python των βιβλιοθηκών τρίτων, όπως για τη μηχανική μάθηση, έχουν τον κώδικα C στον πυρήνα τους.

Εάν η ταχύτητα ανάπτυξης έχει μεγαλύτερη σημασία από την ταχύτητα εκτέλεσης, και εάν τα περισσότερα από τα εκτελέσιμα μέρη του προγράμματος μπορούν να απομονωθούν σε αυτόνομα στοιχεία (σε αντίθεση με την εξάπλωση σε ολόκληρο τον κώδικα), δημιουργούνται είτε καθαρά Python είτε συνδυασμοί βιβλιοθηκών Python και C μια καλύτερη επιλογή από το C μόνο. Διαφορετικά, ο Γ εξακολουθεί να ισχύει.