Ich überlege mir, C. zu lernen.
Aber warum verwenden die Leute C (oder C ++), wenn es "gefährlich" verwendet werden kann?
Mit gefährlich meine ich mit Zeigern und ähnlichem Zeug.
Wie die Stapelüberlauf-Frage Warum ist die gets-Funktion so gefährlich, dass sie nicht verwendet werden sollte? . Warum verwenden Programmierer nicht einfach Java oder Python oder eine andere kompilierte Sprache wie Visual Basic?
Antworten:
C ist älter als viele andere Sprachen, an die Sie denken. Vieles, was wir jetzt wissen, um das Programmieren "sicherer" zu machen, kommt aus der Erfahrung mit Sprachen wie C.
Viele der sichereren Sprachen, die seit C herausgekommen sind, basieren auf einer größeren Laufzeit, einem komplizierteren Funktionsumfang und / oder einer virtuellen Maschine, um ihre Ziele zu erreichen. Infolgedessen ist C so etwas wie ein "kleinster gemeinsamer Nenner" unter allen populären / Mainstream-Sprachen geblieben.
C ist eine Sprache, die viel einfacher zu implementieren ist, da sie relativ klein ist und selbst in der schwächsten Umgebung mit größerer Wahrscheinlichkeit eine angemessene Leistung erbringt. Daher ist es für viele eingebettete Systeme, die ihre eigenen Compiler und andere Tools entwickeln müssen, wahrscheinlicher, dass sie einen funktionsfähigen Compiler bereitstellen für C.
Da C so klein und einfach ist, kommunizieren andere Programmiersprachen in der Regel über eine C-ähnliche API miteinander. Dies ist wahrscheinlich der Hauptgrund, warum C niemals wirklich sterben wird, selbst wenn die meisten von uns immer nur durch Wrapper damit interagieren.
Viele der "sichereren" Sprachen, die versuchen, C und C ++ zu verbessern, versuchen nicht, "Systemsprachen" zu sein, mit denen Sie die Speichernutzung und das Laufzeitverhalten Ihres Programms nahezu vollständig steuern können. Zwar benötigen heutzutage immer mehr Anwendungen einfach nicht diese Kontrollebene, doch es wird immer eine kleine Handvoll Fälle geben, in denen dies erforderlich ist (insbesondere in den virtuellen Maschinen und Browsern, die all diese netten, sicheren Sprachen für das Internet implementieren) Wir Übrigen).
Heutzutage gibt es einige Systemprogrammiersprachen (Rust, Nim, D, ...), die sicherer als C oder C ++ sind. Sie haben im Nachhinein den Vorteil, dass eine solche Feinsteuerung in den meisten Fällen nicht erforderlich ist. Bieten Sie daher eine allgemein sichere Schnittstelle mit ein paar unsicheren Hooks / Modi, auf die Sie bei Bedarf umschalten können.
Sogar innerhalb von C haben wir eine Menge Regeln und Richtlinien gelernt, die dazu neigen, die Anzahl heimtückischer Fehler, die in der Praxis auftreten, drastisch zu reduzieren. Es ist im Allgemeinen unmöglich, den Standard dazu zu bringen, diese Regeln rückwirkend durchzusetzen, da dies zu viel vorhandenen Code beschädigen würde. Es ist jedoch üblich, Compiler-Warnungen, Linters und andere statische Analysetools zu verwenden, um diese Art von leicht vermeidbaren Problemen zu erkennen. Die Untermenge von C-Programmen, die diese Tools mit Bravour bestehen, ist bereits weitaus sicherer als "nur C", und jeder kompetente C-Programmierer wird heutzutage einige von ihnen verwenden.
Außerdem werden Sie niemals einen verschleierten Java-Wettbewerb so unterhaltsam machen wie den verschleierten C-Wettbewerb .
quelle
Erstens ist C eine Systemprogrammiersprache. Wenn Sie beispielsweise eine Java Virtual Machine oder einen Python-Interpreter schreiben, benötigen Sie eine Systemprogrammiersprache, um sie zu schreiben.
Zweitens bietet C eine Leistung, die Sprachen wie Java und Python nicht bieten. In der Regel werden beim Hochleistungsrechnen in Java und Python Bibliotheken verwendet, die in einer Hochleistungssprache wie C geschrieben sind, um das schwere Heben durchzuführen.
Drittens hat C eine viel kleinere Stellfläche als Sprachen wie Java und Python. Dies macht es für eingebettete Systeme verwendbar, die möglicherweise nicht über die erforderlichen Ressourcen verfügen, um die großen Laufzeitumgebungen und den Speicherbedarf von Sprachen wie Java und Python zu unterstützen.
Eine "Systemprogrammiersprache" ist eine Sprache, mit der sich industrietaugliche Systeme aufbauen lassen. Java und Python sind derzeit keine Systemprogrammiersprachen. "Genau das, was eine Systemprogrammiersprache ausmacht" ist nicht Gegenstand dieser Frage, aber eine Systemprogrammiersprache muss Unterstützung für die Arbeit mit der zugrunde liegenden Plattform bieten.
Andererseits muss eine Systemprogrammiersprache (als Antwort auf Kommentare) nicht selbsthostend sein. Dieses Problem trat auf , weil die ursprüngliche Frage gestellt „ warum die Leute C verwenden“, der erste Kommentar gefragt : „Warum würden Sie eine Sprache wie C benötigen“ , wenn Sie PyPy haben, und ich stellte fest , dass PyPy ist in der Tat C. verwenden Sie es also, war ursprünglich relevant für die Frage, aber leider (und verwirrend) ist "Selbsthosting" für diese Antwort nicht relevant. Es tut mir leid, dass ich es angesprochen habe.
Zusammenfassend lässt sich sagen, dass Java und Python nicht für die Systemprogrammierung geeignet sind, nicht weil ihre primären Implementierungen interpretiert werden oder weil nativ kompilierte Implementierungen nicht selbst gehostet werden, sondern weil sie nicht die erforderliche Unterstützung für die Arbeit mit der zugrunde liegenden Plattform bieten.
quelle
Es tut uns leid, noch eine Antwort hinzuzufügen, aber ich glaube, keine der vorhandenen Antworten spricht direkt Ihren ersten Satz an und lautet:
Warum? Möchten Sie die Dinge tun, für die C heutzutage normalerweise verwendet wird (z. B. Gerätetreiber, VMs, Game Engines, Medienbibliotheken, eingebettete Systeme, Betriebssystemkernel)?
Wenn ja, dann ja, lernen Sie C oder C ++, je nachdem, für wen Sie sich interessieren. Möchten Sie es lernen, damit Sie ein tieferes Verständnis dafür haben, was Ihre Hochsprache tut?
Anschließend erwähnen Sie die Sicherheitsbedenken. Sie brauchen nicht unbedingt ein tiefes Verständnis für sicheres C, um Letzteres zu tun, so wie ein Codebeispiel in einer höheren Sprache Ihnen das Wesentliche vermitteln könnte, ohne produktionsbereit zu sein.
Schreiben Sie einen C-Code, um das Wesentliche herauszufinden. Dann legen Sie es wieder in das Regal. Sorgen Sie sich nicht zu sehr um die Sicherheit, es sei denn, Sie möchten Produktions- C-Code schreiben .
quelle
Dies ist eine RIESIGE Frage mit Tonnen von Antworten, aber die Kurzversion ist, dass jede Programmiersprache für verschiedene Situationen spezialisiert ist. Zum Beispiel JavaScript für das Web, C für Dinge auf niedriger Ebene, C # für alles Windows usw. Es ist hilfreich zu wissen, was Sie tun möchten, sobald Sie mit der Programmierung vertraut sind, um zu entscheiden, welche Programmiersprache Sie auswählen möchten.
Um Ihren letzten Punkt anzusprechen, warum C / C ++ über Java / Python, kommt es oft auf die Geschwindigkeit an. Ich mache Spiele, und Java / C # erreicht erst kürzlich Geschwindigkeiten, die gut genug sind, um Spiele auszuführen. Wenn Sie möchten, dass Ihr Spiel mit 60 Bildern pro Sekunde läuft und dass Ihr Spiel viel leistet (Rendering ist besonders teuer), müssen Sie den Code so schnell wie möglich ausführen. Python / Java / C # / Viele andere verwenden "Interpreter", eine zusätzliche Softwareschicht, die all die mühsamen Dinge handhabt, die C / C ++ nicht tut, z. B. das Verwalten von Speicher und die Garbage Collection. Dieser zusätzliche Aufwand verlangsamt die Arbeit, sodass fast jedes große Spiel, das Sie sehen, (jedenfalls in den letzten 10 Jahren) in C oder C ++ ausgeführt wurde. Es gibt Ausnahmen: Die Unity-Spiele-Engine verwendet C # * und Minecraft Java, aber dies ist die Ausnahme, nicht die Regel. Im Allgemeinen,
* Auch Unity ist nicht alles in C #, große Teile davon sind C ++ und Sie verwenden einfach C # für Ihren Spielcode.
BEARBEITEN Um auf einige der Kommentare zu antworten, die auftauchten, nachdem ich dies gepostet hatte: Vielleicht habe ich zu viel vereinfacht, ich habe nur ein allgemeines Bild gegeben. Bei der Programmierung ist die Antwort nie einfach. Es gibt Interpreter für C, Javascript kann außerhalb des Browsers ausgeführt werden und C # kann dank Mono auf fast allem ausgeführt werden. Verschiedene Programmiersprachen sind auf verschiedene Domänen spezialisiert, aber einige Programmierer haben wahrscheinlich herausgefunden, wie man eine Sprache in einem beliebigen Kontext zum Laufen bringt. Da das OP nicht viel über Programmierung zu wissen schien (Annahme meinerseits, sorry, wenn ich mich irre), versuchte ich, meine Antwort einfach zu halten.
In Bezug auf die Kommentare zu C #, das fast so schnell ist wie C ++, gibt es fast das Schlüsselwort. Als ich auf dem College war, haben wir viele Spielefirmen besucht, und mein Lehrer (der uns das ganze Jahr über dazu ermutigt hatte, von C # auf C ++ umzusteigen) hat Programmierer bei jeder Firma gefragt, warum C ++ über C # und bei jeder einzelnen sagte C # ist zu langsam. Im Allgemeinen läuft es schnell, aber der Garbage Collector kann die Leistung beeinträchtigen, da Sie nicht kontrollieren können, wann es ausgeführt wird, und er hat das Recht, Sie zu ignorieren, wenn es nicht ausgeführt werden soll, wenn Sie es empfehlen. Wenn Sie etwas brauchen, um eine hohe Leistung zu erzielen, möchten Sie nicht, dass etwas so unvorhersehbar ist.
Um auf meinen Kommentar zu antworten, dass ich gerade erst die Geschwindigkeit erreicht habe, sind viele der Geschwindigkeitssteigerungen in C # auf bessere Hardware zurückzuführen. Da sich jedoch das .NET Framework und der C # -Compiler verbessert haben, wurden einige Geschwindigkeitssteigerungen durchgeführt.
Über den Kommentar "Spiele sind in der gleichen Sprache wie die Engine geschrieben" kommt es darauf an. Einige sind, aber viele sind in einer Mischung von Sprachen geschrieben. Unreal kann UnrealScript und C ++, Unity C # Javascript und Boo, viele andere in C oder C ++ geschriebene Engines verwenden Python oder Lua als Skriptsprachen. Da gibt es keine einfache Antwort.
Und nur weil es mich nervte, zu lesen, "Wen interessiert es, ob Ihr Spiel mit 200 fps oder 120 fps läuft", wenn Ihr Spiel schneller als 60 fps läuft, verschwenden Sie wahrscheinlich CPU-Zeit, da der durchschnittliche Monitor dies nicht einmal aktualisiert schnell. Einige High-End- und neuere Versionen sind verfügbar, aber (noch) nicht Standard.
Und was die Bemerkung angeht, dass ich Jahrzehnte der Technik ignoriere, bin ich noch in den frühen 20ern. Wenn ich also rückwärts extrapoliere, spreche ich hauptsächlich von dem, was ältere und erfahrenere Programmierer mir erzählt haben. Natürlich wird das auf einer Seite wie dieser bestritten, aber es lohnt sich, darüber nachzudenken.
quelle
Es ist lustig, dass Sie behaupten, C sei unsicher, weil "es Zeiger hat". Das Gegenteil ist der Fall: Java und C # haben praktisch nur Zeiger (für nicht native Typen). Der häufigste Fehler in Java ist wahrscheinlich die Null-Zeiger-Ausnahme (siehe https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). Der zweithäufigste Fehler ist wahrscheinlich, dass versteckte Verweise auf nicht verwendete Objekte (z. B. geschlossene Dialoge werden nicht entsorgt) vorhanden sind, die daher nicht freigegeben werden können, was zu lang laufenden Programmen mit einem ständig wachsenden Speicherbedarf führt.
Es gibt zwei grundlegende Mechanismen, die C # und Java auf zwei verschiedene Arten sicherer machen:
Aktuelle C ++ - Zeiger erleichtern den Programmierern diese Arbeit.
Die Laufzeit schützt nicht vor zB versuchten Pufferüberläufen, erlaubt aber theoretisch keine Exploits solcher Programme. Bei C und C ++ muss der Programmierer dagegen sicher codieren, um Exploits zu verhindern. Dies wird in der Regel nicht sofort erreicht, sondern erfordert Überprüfungen und Iterationen.
Es ist jedoch zu beachten, dass die aufwendige Laufzeit auch ein Sicherheitsrisiko darstellt. Es scheint mir, dass Oracle die JVM aufgrund neu entdeckter Sicherheitsprobleme alle paar Wochen aktualisiert. Es ist natürlich viel schwieriger , die JVM zu überprüfen als ein einzelnes Programm.
Die Sicherheit einer aufwändigen Laufzeit ist daher mehrdeutig und zu einem gewissen Grad trügerisch: Ihr durchschnittliches C-Programm kann mit Überprüfungen und Iterationen einigermaßen sicher gemacht werden. Ihr durchschnittliches Java-Programm ist nur so sicher wie die JVM. das ist nicht wirklich. Noch nie.
Der Artikel
gets()
, auf den Sie über diesen Link verweisen, spiegelt historische Bibliotheksentscheidungen wider, die heute anders getroffen würden, nicht die Kernsprache.quelle
Weil "Sicherheit" Geschwindigkeit kostet, arbeiten die "sichereren" Sprachen langsamer.
Sie fragen, warum Sie eine "gefährliche" Sprache wie C oder C ++ verwenden, jemand Ihnen einen Grafiktreiber oder ähnliches in Python oder Java usw. schreiben lassen und sehen, wie Sie sich in Bezug auf "Sicherheit" fühlen :)
Im Ernst, Sie müssen so nah am Hauptspeicher der Maschine sein, um Pixel, Register usw. manipulieren zu können. Java oder Python können dies nicht mit jeder Art von leistungsfähiger Geschwindigkeit ... C und C ++ beides Ermöglichen Sie dies durch Zeiger und dergleichen zu tun ...
quelle
Neben alledem gibt es auch einen ziemlich häufigen Anwendungsfall, bei dem C als gemeinsame Bibliothek für andere Sprachen verwendet wird.
Grundsätzlich haben fast alle Sprachen eine API-Schnittstelle zu C.
Einfaches Beispiel: Versuchen Sie, eine gemeinsame Anwendung für Linux / IOS / Android / Windows zu erstellen. Abgesehen von all den Tools, die es gibt, haben wir am Ende eine Kernbibliothek in C erstellt und dann die GUI für jede Umgebung geändert:
Meine zwei Cent,
quelle
Eine grundlegende Schwierigkeit bei C besteht darin, dass der Name verwendet wird, um eine Reihe von Dialekten mit identischer Syntax, aber sehr unterschiedlicher Semantik zu beschreiben. Einige Dialekte sind viel sicherer als andere.
In C, wie es ursprünglich von Dennis Ritchie entworfen wurde, würden C-Anweisungen im Allgemeinen in vorhersagbarer Weise auf Maschinenbefehle abgebildet. Da C auf Prozessoren ausgeführt werden kann, die sich anders verhalten, wenn ein vorzeichenbehafteter arithmetischer Überlauf auftritt, weiß ein Programmierer, der nicht weiß, wie sich eine Maschine im Falle eines arithmetischen Überlaufs verhält, auch nicht, welcher C-Code auf dieser Maschine ausgeführt wird Wenn bekannt ist, dass sich eine Maschine auf eine bestimmte Art und Weise verhält (z. B. ein stiller Wraparound mit zwei Komplementen), können Implementierungen auf dieser Maschine in der Regel ebenfalls ausgeführt werden. Einer der Gründe, warum C für seine Schnelligkeit bekannt war, war, dass in Fällen, in denen Programmierer wussten, dass das natürliche Verhalten einer Plattform in Edge-Case-Szenarien ihren Anforderungen entspricht, der Programmierer oder Compiler keinen Code schreiben musste, um solche Szenarien zu generieren .
Leider haben Compiler-Autoren die Ansicht vertreten, dass Compiler sich frei fühlen sollten, Code zu generieren, der Gesetze negiert, da der Standard in solchen Fällen keine Anforderungen an die Implementierung stellt (Laxität, die Hardware-Implementierungen ermöglichen sollte, die sich möglicherweise nicht vorhersehbar verhalten) von Zeit und Kausalität.
Betrachten Sie etwas wie:
Hypermoderne (aber modische) Compilertheorie würde vorschlagen, dass der Compiler "QUACK!" Bedingungslos, da in jedem Fall, in dem die Bedingung falsch war, das Programm undefiniertes Verhalten aufrief und eine Multiplikation durchführte, deren Ergebnis ohnehin ignoriert werden würde. Da der Standard einem Compiler in einem solchen Fall erlauben würde, alles zu tun, was er möchte, kann der Compiler "QUACK!" Ausgeben.
Während C früher sicherer war als die Assemblersprache, ist bei der Verwendung von hochmodernen Compilern das Gegenteil der Fall. In der Assemblersprache kann ein Ganzzahlüberlauf dazu führen, dass eine Berechnung zu einem bedeutungslosen Ergebnis führt. Auf den meisten Plattformen ist dies jedoch das Ausmaß der Auswirkungen. Wenn die Ergebnisse trotzdem ignoriert werden, spielt der Überlauf keine Rolle. In hypermodernem C können jedoch auch normalerweise "harmlose" Formen von Undefiniertem Verhalten (wie ein ganzzahliger Überlauf in einer Berechnung, der letztendlich ignoriert wird) eine willkürliche Programmausführung verursachen.
quelle
int arr[5][[5]
Zugriffsversuch z. B.arr[0][5]
undefiniertes Verhalten zur Folge hat. Eine solche Regel macht es möglich, dass ein Compiler, dem so etwas wiearr[1][0]=3; arr[0][i]=6; arr[1][0]++;
der Schluss gegebenarr[1][0]
wird, gleich 4 ist, ohne Rücksicht auf den Wert voni
.Historische Gründe. Ich kann nicht oft brandneuen Code schreiben, meistens kann ich das alte Zeug, das seit Jahrzehnten läuft, warten und erweitern. Ich bin nur froh, dass es C ist und nicht Fortran.
Ich kann mich ärgern, wenn ein Student sagt: "Aber warum machst du dieses schreckliche X, wenn du Y machen könntest?". Nun, X ist der Job, den ich habe, und er zahlt die Rechnungen sehr gut. Ich habe gelegentlich Y gemacht und es hat Spaß gemacht, aber X ist das, was die meisten von uns tun.
quelle
Was ist "gefährlich"?
Die Behauptung, C sei "gefährlich", ist ein häufiges Gesprächsthema in Sprachflammenkriegen (am häufigsten im Vergleich zu Java). Die Beweise für diese Behauptung sind jedoch unklar.
C ist eine Sprache mit bestimmten Funktionen. Einige dieser Funktionen können bestimmte Arten von Fehlern zulassen, die von anderen Arten von Sprachen nicht zugelassen werden (das Risiko der Speicherverwaltung von C wird normalerweise hervorgehoben). Dies ist jedoch nicht das gleiche wie ein Argument , das C gefährlicher als andere Sprachen ist insgesamt . Mir ist nicht bekannt, dass jemand in diesem Punkt überzeugende Beweise liefert.
Ebenfalls, „gefährlich“ ist abhängig von Kontext: Was Sie versuchen zu tun, und welche Arten von Risiken sind Sie besorgt über?
In vielen Zusammenhängen würde ich C für "gefährlicher" halten als eine Hochsprache, da Sie die grundlegenden Funktionen mehr manuell implementieren müssen, um das Risiko von Fehlern zu erhöhen. Zum Beispiel wäre eine einfache Textverarbeitung oder die Entwicklung einer Website in C normalerweise dumm, da andere Sprachen über Funktionen verfügen, die dies erheblich vereinfachen.
C und C ++ werden jedoch häufig für unternehmenskritische Systeme verwendet, da eine kleinere Sprache mit direkterer Kontrolle über die Hardware in diesem Zusammenhang als "sicherer" angesehen wird. Aus einer sehr guten Stack Overflow-Antwort :
quelle
Um die vorhandenen Antworten zu ergänzen, ist es gut und schön zu sagen, dass Sie sich für Python oder PHP für Ihr Projekt entscheiden, da diese relativ sicher sind. Aber irgendjemand muss diese Sprachen implementieren und wenn, dann werden sie es wahrscheinlich in C tun. (Oder so ähnlich.)
Aus diesem Grund verwenden die Benutzer C - , um die weniger gefährlichen Tools zu erstellen, die Sie verwenden möchten.
quelle
Gestatten Sie mir, Ihre Frage neu zu formulieren:
Jedes interessante Tool kann gefährlich eingesetzt werden, einschließlich Programmiersprachen. Sie lernen mehr, damit Sie es tun können können (und damit weniger Gefahr entsteht, wenn Sie das Tool verwenden). Insbesondere lernen Sie das Werkzeug, damit Sie das tun können, wofür das Werkzeug gut ist (und vielleicht erkennen, wann dieses Werkzeug das beste Werkzeug der Ihnen bekannten Werkzeuge ist).
Wenn Sie beispielsweise ein 5 cm tiefes, zylindrisches Loch mit 6 mm Durchmesser in einen Holzblock stecken müssen, ist ein Bohrer ein viel besseres Werkzeug als ein LALR-Parser. Wenn Sie wissen, was diese beiden Werkzeuge sind, wissen Sie, welches das richtige Werkzeug ist. Wenn Sie bereits wissen, wie man einen Bohrer benutzt, voila !, hole.
C ist nur ein weiteres Werkzeug. Es ist für einige Aufgaben besser als für andere. Die anderen Antworten hier sprechen dies an. Wenn Sie etwas C lernen, werden Sie erkennen, wann es das richtige Werkzeug ist und wann nicht.
quelle
Es gibt keinen bestimmten Grund, C nicht zu lernen, aber ich würde C ++ vorschlagen. Es bietet viel von dem, was C kann (da C ++ eine super Menge von C ist), mit einer großen Menge von "Extras". Das Erlernen von C vor C ++ ist nicht erforderlich - es handelt sich effektiv um separate Sprachen.
Anders ausgedrückt, wenn C eine Reihe von Holzbearbeitungswerkzeugen wäre, wäre es wahrscheinlich:
Mit diesen Tools können Sie alles erstellen - aber alles, was gut ist, erfordert möglicherweise viel Zeit und Können.
C ++ ist die Sammlung von Elektrowerkzeugen in Ihrem örtlichen Baumarkt.
Wenn Sie sich zunächst an die grundlegenden Sprachfunktionen halten, hat C ++ relativ wenig zusätzlichen Lernaufwand.
Weil manche Leute keine Möbel von IKEA wollen. =)
Im Ernst, obwohl viele Sprachen, die "höher" als C oder C ++ sind, Dinge haben, die sie (möglicherweise) in bestimmten Aspekten "einfacher" machen, ist dies nicht immer eine gute Sache. Wenn Ihnen die Art und Weise, wie etwas getan wird oder eine Funktion nicht bereitgestellt wird, nicht gefällt, können Sie wahrscheinlich nicht viel dagegen tun. Auf der anderen Seite bieten C und C ++ genügend "Low-Level" -Sprachenfunktionen (einschließlich Zeigern), mit denen Sie auf viele Dinge ziemlich direkt (insbesondere Hardware oder Betriebssystem) zugreifen oder sie selbst erstellen können, was in anderen möglicherweise nicht möglich ist Sprachen wie implementiert.
Insbesondere hat C die folgenden Funktionen, die es für viele Programmierer wünschenswert machen:
Kompatibilität - C gibt es schon lange und jeder hat Tools und Bibliotheken dafür. Die Sprache selbst ist auch nicht wählerisch - sie erwartet von einem Prozessor, dass er Anweisungen ausführt und Speicher, um Dinge zu speichern, und das ist alles.
Darüber hinaus gibt es ein so genanntes Application Binary Interface (ABI) . Kurz gesagt, es ist eine Möglichkeit für Programme, auf Maschinencodeebene zu kommunizieren, was Vorteile gegenüber einer Anwendungsprogrammierschnittstelle (Application Programming Interface, API) haben kann . Während andere Sprachen wie C ++ eine ABI haben können, sind diese normalerweise weniger einheitlich (vereinbart) als die von C, so dass C eine gute Basissprache ist, wenn Sie eine ABI verwenden möchten, um aus irgendeinem Grund mit einem anderen Programm zu kommunizieren.
Effizienz (und gelegentlich Speicherverwaltungsschemata, die ohne relativ direkten Speicherzugriff nicht implementiert werden können).
Der direkte Zugriff auf das Gedächtnis mit Zeigern bringt eine Menge netter (normalerweise schneller) Tricks mit sich, wenn Sie Ihre schmutzigen Pfoten direkt auf die kleinen Einsen und Nullen in Ihren Gedächtnisräumen setzen und nicht darauf warten müssen, dass der alte Lehrer das Spielzeug einfach austeilt zur spielzeit schaufeln sie sie dann wieder auf.
Kurz gesagt, das Hinzufügen von Dingen kann zu Verzögerungen führen oder auf andere Weise zu unerwünschter Komplexität.
In Bezug auf Skriptsprachen und Ähnliches müssen Sie hart arbeiten, um Sprachen zu erhalten, für die sekundäre Programme so effizient ausgeführt werden müssen wie C (oder eine kompilierte Sprache). Das Hinzufügen eines Interpreters im laufenden Betrieb bietet die Möglichkeit, die Ausführungsgeschwindigkeit zu verringern und den Speicherbedarf zu erhöhen, da Sie der Mischung ein anderes Programm hinzufügen. Die Effizienz Ihres Programms hängt ebenso stark von der Effizienz dieses sekundären Programms ab wie davon, wie gut (schlecht =) Sie Ihren ursprünglichen Programmcode geschrieben haben. Ganz zu schweigen davon, dass Ihr Programm oft vollständig darauf angewiesen ist, dass das zweite Programm überhaupt ausgeführt wird. Das zweite Programm existiert aus irgendeinem Grund nicht auf einem bestimmten System? Code no go.
In der Tat, die Einführung etwas „extra“ verlangsamt potenziell oder kompliziert Ihren Code. In Sprachen „ohne beängstigend Zeiger“, warten Sie immer für andere Teile des Codes hinter sich aufzuräumen oder auf andere Weise herausfinden „sicher“ Möglichkeiten , Dinge zu tun - weil Ihr Programm immer noch die gleichen Speicherzugriffsoperationen zu tun wie es mit getan werden Zeiger. Sie sind einfach nicht derjenige, der damit umgeht (Sie können es also nicht ficken, Genie = P).
Nach der akzeptierten Antwort:
Die Vorstellung, dass etwas in einer Sprache getan werden kann, muss es , ist dumm. Sprachen haben Fehler, die behoben werden. Aus Kompatibilitätsgründen mit älterem Code kann dieses Konstrukt weiterhin verwendet werden. Es gibt jedoch (wahrscheinlich) nichts, was einen Programmierer dazu zwingt, gets () zu verwenden, und tatsächlich wurde dieser Befehl im Wesentlichen durch sicherere Alternativen ersetzt.
Genauer gesagt ist das Problem mit gets () kein Zeigerproblem per se Zeigerproblem. Es ist ein Problem mit einem Befehl, der nicht unbedingt weiß, wie man Speicher sicher verwendet. In einem abstrakten Sinne sind dies alles Zeigerfragen - Lesen und Schreiben von Dingen, die Sie nicht sollten. Das ist kein Problem mit Zeigern; Es ist ein Problem mit der Zeiger-Implementierung.
Zur Verdeutlichung sind Zeiger erst dann gefährlich, wenn Sie versehentlich auf einen Speicherort zugreifen, den Sie nicht beabsichtigt haben. Und selbst dann ist nicht garantiert, dass Ihr Computer schmilzt oder explodiert. In den meisten Fällen funktioniert Ihr Programm nicht mehr (korrekt).
Da Zeiger den Zugriff auf Speicherorte ermöglichen und Daten und ausführbarer Code zusammen im Speicher vorhanden sind, besteht jedoch die Gefahr einer versehentlichen Beschädigung, dass Sie den Speicher ordnungsgemäß verwalten möchten.
Da Operationen mit direktem Speicherzugriff im Allgemeinen häufig weniger Vorteile bieten als noch vor Jahren, haben selbst Sprachen ohne Speicherbereinigung wie C ++ Funktionen wie intelligente Zeiger eingeführt , um die Lücke zwischen Speichereffizienz und Sicherheit zu schließen.
Zusammenfassend lässt sich sagen, dass es sehr wenig Grund gibt, den Zeiger zu fürchten, solange er sicher verwendet wird. Nehmen Sie einfach einen Hinweis von South Parks Version von Steve "The Crocodile Hunter" Irwin - stecken Sie Ihren Daumen nicht in die Irrenlöcher der Crocs .
quelle
Wie immer ist die Programmiersprache nur eine Folge der Problemlösung. Sie sollten in der Tat nicht nur C lernen, sondern auch viele verschiedene Sprachen (und andere Möglichkeiten zur Programmierung eines Computers, seien es GUI-Tools oder Befehlsinterpreter), um eine anständige Toolbox zur Lösung von Problemen zu haben.
Manchmal werden Sie feststellen, dass sich ein Problem gut für etwas eignet, das in den Java-Standardbibliotheken enthalten ist. In diesem Fall können Sie Java auswählen, um dies zu nutzen. In anderen Fällen müssen Sie unter Windows möglicherweise etwas tun, das in der .NET-Laufzeit viel einfacher ist, sodass Sie möglicherweise C # oder VB verwenden. Möglicherweise gibt es ein grafisches Tool oder ein Befehlsskript, das Ihr Problem löst, und Sie können diese verwenden. Möglicherweise müssen Sie eine GUI-Anwendung auf mehreren Plattformen schreiben. Aufgrund der im JDK enthaltenen Bibliotheken kann Java eine Option sein. Andererseits fehlt einer Zielplattform möglicherweise eine JRE. Wählen Sie stattdessen C und SDL (oder eine ähnliche).
C hat eine wichtige Position in diesem Toolset, da es allgemein, klein und schnell ist und auch zu Maschinencode kompiliert. Es wird auch auf jeder Plattform unter der Sonne unterstützt (jedoch nicht ohne Neukompilierung).
Fazit ist, dass Sie so viele Tools, Sprachen und Paradigmen lernen sollten, wie Sie nur können.
Bitte entfernen Sie sich von der Einstellung: "Ich bin ein X-Programmierer" (X = C, C ++, Java usw.)
Verwenden Sie einfach "Ich bin ein Programmierer".
Ein Programmierer löst Probleme und entwirft Algorithmen, indem er Maschinen anweist, die Arbeitslast auszuführen. Ende der Geschichte. Dies ist für die Sprache irrelevant. Ihre wichtigste Fähigkeit ist das Lösen von Problemen und die logische Aufschlüsselung strukturierter Probleme. Sprachkenntnisse / Sprachwahl sind IMMER zweitrangig und / oder eine Folge der Art des Problems.
Ein interessanter Weg, wenn Sie an C interessiert sind, ist es, Ihre Fähigkeiten mit Go zu erweitern. Go ist wirklich ein verbessertes C mit Garbage Collection und Interfaces sowie einem netten eingebauten Threading-Modell / -Kanälen, das auch viele der Vorteile von C mit sich bringt (wie Zeigerarithmetik und Kompilieren von Maschinencode).
quelle
Es hängt davon ab, was Sie damit vorhaben. C wurde als Ersatz für Assemblersprache entwickelt und ist die Hochsprache, die der Maschinensprache am nächsten kommt. Daher hat es einen geringen Overhead in Bezug auf Größe und Leistung und eignet sich für die Systemprogrammierung und andere Aufgaben, die einen geringen Platzbedarf erfordern und sich der zugrunde liegenden Hardware nähern.
quelle
Wenn Sie auf der Ebene der Bits und Bytes, des Speichers als homogene Rohdatensammlung arbeiten, wie es häufig erforderlich ist, um die effizientesten Allokatoren und Datenstrukturen effektiv zu implementieren, ist keine Sicherheit zu haben. Sicherheit ist in erster Linie ein stark datentypbezogenes Konzept, und ein Speicherzuweiser funktioniert nicht mit Datentypen. Es arbeitet mit Bits und Bytes, um dieselben Bits und Bytes zusammenzufassen, die möglicherweise einen Datentyp zu einem bestimmten Zeitpunkt und zu einem späteren Zeitpunkt darstellen.
In diesem Fall spielt es keine Rolle, ob Sie C ++ verwenden. Sie würden immer noch den
static_casts
gesamten Code ausvoid*
Zeigern streuen und immer noch mit Bits und Bytes arbeiten und einfach mehr Probleme im Zusammenhang mit dem Respektieren des Typsystems in diesem Kontext haben als C, das ein viel einfacheres Typsystem hat, in dem Sie frei sind ummemcpy
Bits und Bytes herum, ohne über das Typensystem Bulldozing zu sorgen.Tatsächlich ist es oft schwieriger, in C ++, einer insgesamt sichereren Sprache, in solch einfachen Kontexten von Bits und Bytes zu arbeiten, ohne noch gefährlicheren Code zu schreiben als in C, da Sie über das Typensystem von C ++ hinwegblödeln und Dinge wie tun könnten Überschreiben von vptrs und Nichtaufrufen von Konstruktoren und Destruktoren für Kopien zu geeigneten Zeiten. Wenn Sie sich die Zeit nehmen, diese Typen zu respektieren und die Platzierung neu und manuell aufzurufen usw., werden Sie mit der Welt der Ausnahmebehandlung in einem Kontext konfrontiert, der für RAII zu niedrig ist, um praktisch zu sein, und Ausnahmebedingungen zu erreichen. Sicherheit in solch einem Kontext auf niedriger Ebene ist sehr schwierig (Sie müssen so tun, als ob fast jede Funktion alle Möglichkeiten auslotet und abfängt und alle Nebenwirkungen als unteilbare Transaktion zurückwirft, als ob nichts passiert wäre). Der C-Code kann oft "
Und es wäre unmöglich, solche Allokatoren in Sprachen zu implementieren, die es Ihnen nicht erlauben, hier "gefährlich" zu werden. Sie müssten sich auf die von ihnen bereitgestellten Allokatoren stützen (die höchstwahrscheinlich in C oder C ++ implementiert sind) und hoffen, dass sie für Ihre Zwecke gut genug sind. Und es gibt fast immer effizientere, aber weniger allgemeine Allokatoren und Datenstrukturen, die für Ihre spezifischen Zwecke geeignet sind, die jedoch viel enger anwendbar sind, da sie speziell auf Ihre Zwecke zugeschnitten sind.
Die meisten Leute brauchen kein C oder C ++, da sie nur Code aufrufen können, der ursprünglich in C oder C ++ implementiert war, oder möglicherweise sogar Assembler, der bereits für sie implementiert war. Viele könnten von Innovationen auf hoher Ebene profitieren, wie dem Zusammenfügen eines Bildprogramms, das nur Bibliotheken vorhandener Bildverarbeitungsfunktionen verwendet, die bereits in C implementiert sind, wo sie auf der niedrigsten Ebene des Durchlaufens einzelner Pixel weniger innovativ sind, aber möglicherweise Bietet eine sehr benutzerfreundliche Oberfläche und einen Workflow, der noch nie zuvor gesehen wurde. In diesem Fall ist es möglicherweise eine vorzeitige Optimierung , wenn die Software nur versucht, übergeordnete Aufrufe in untergeordneten Bibliotheken auszuführen ( "Verarbeiten Sie das gesamte Bild für mich und nicht für jedes Pixel. Tun Sie etwas" ) zu versuchen, einen solchen Antrag in C zu schreiben.
Wenn Sie jedoch auf niedriger Ebene etwas Neues tun, bei dem der Zugriff auf Daten auf niedriger Ebene erleichtert wird, beispielsweise durch einen brandneuen Bildfilter, der noch nie zuvor gesehen wurde und der schnell genug ist, um HD-Videos in Echtzeit zu bearbeiten, müssen Sie im Allgemeinen auf Folgendes zugreifen ein bisschen gefährlich.
Es ist einfach, dieses Zeug für selbstverständlich zu halten. Ich erinnere mich an einen Facebook-Beitrag, in dem jemand darauf hinwies, wie es möglich ist, mit Python ein 3D-Videospiel zu erstellen, das impliziert, dass Sprachen auf niedriger Ebene veraltet sind, und das mit Sicherheit ein anständiges Spiel war. Aber Python hat hochrangige Aufrufe in in C implementierten Bibliotheken durchgeführt, um die ganze schwere Arbeit zu erledigen. Sie können Unreal Engine 4 nicht einfach erstellen, indem Sie übergeordnete Aufrufe in vorhandene Bibliotheken tätigen. Unwirkliche Maschine 4 istdie Bibliothek. Es hat alle Arten von Dingen erledigt, die es in anderen Bibliotheken und Engines nie gegeben hat, von der Beleuchtung bis hin zu seinem knotigen Blaupausen-System und wie es Code im laufenden Betrieb kompilieren und ausführen kann. Wenn Sie Innovationen auf einer niedrigen Engine- / Core- / Kernel-Ebene durchführen möchten, müssen Sie auf einer niedrigen Ebene arbeiten. Wenn alle Spieleentwickler auf sichere Hochsprachen umstellen würden, gäbe es keine Unreal Engine 5, 6 oder 7. Wahrscheinlich werden die Leute Unreal Engine 4 Jahrzehnte später noch verwenden, weil Sie nicht auf dem erforderlichen Niveau innovieren können raus mit einem Next-Gen-Motor, indem Sie nur hochrangige Anrufe in den alten machen.
quelle