Was sollte ein C-Programmierer wissen? [geschlossen]
11
Welche Konzepte / Techniken / Sprachfunktionen sollte jeder anständige C-Programmierer kennen / kennen (ausgenommen allgemeine Softwareentwicklung und ähnliches und sich nur auf C-spezifische Dinge konzentrieren). Ich würde gerne wissen, damit ich einige mögliche Lücken in meinem C-Wissen schließen kann.
Beginnen Sie mit den C-Fragen von Stack Overflow und prüfen Sie, ob Sie etwas nicht wissen.
Chrisaycock
3
AC-Programmierer sollte das wahrscheinlich wissen2 + 2 = 4
Edward Strange
21
Sie sollten von einem Geschäft wissen, das kugelsichere Schuhe verkauft.
Adam Crossland
1
Es gibt Hunderte von Büchern zu diesem Thema. Ihre Frage ist wirklich ziemlich vage. Sie müssen spezifischer sein, um anständige Antworten zu erhalten, die nicht nur eine Liste von Dingen sind. Und wenn ich sehe, dass die Antworten so weit von dieser Frage entfernt sind, würde ich denken, dass sie überarbeitet oder geschlossen werden muss.
Walter
2
Eine andere Programmiersprache?
Muhammad Alkarouri
Antworten:
19
Spezifisch für C? Abgesehen von Standardkonstrukten, die den meisten prozeduralen Sprachen gemeinsam sind, muss ich sagen:
(ab) Verwenden des Präprozessors
Linker vs Compiler
Zeiger Zeiger Zeiger!
Wie Arrays Zeiger sind, sind Arrays
Wie C-Strings funktionieren und wie sie auch Zeiger und Arrays sind
Wie schlecht die Verwendung von C-Strings zu Pufferüberläufen führen kann
Wie man irgendetwas in irgendetwas verwandelt (es sind immerhin nur 1s und 0s :))
Manuelle Speicherverwaltung malloc / free
Stapel gegen Haufen
Zeiger-Aliasing (warum es in C99 illegal ist)
Denken Sie an die Entwicklung in Form von Modulen (.h / .c-Dateien) mit einer Reihe öffentlich verfügbarer Funktionen anstelle von strengen Klassen
AC-Programmierer sollten ... andere Sprachen kennen! ;-) Es ist immer fruchtbar, Konzepte aus anderen Sprachen verschiedener Paradigmen zu kennen, wie OOP, funktionale Programmierung und so weiter.
Im Ernst, ein Blick auf den verschleierten Programmierwettbewerb macht Spaß und ist seltsamerweise auch eine gute Erfahrung.
Ich erwähnte "Pufferüberläufe" in einem Kommentar zu Pythagras 'Antwort. Ich sollte wahrscheinlich klarstellen, was ich ein bisschen meinte. In C reicht es nicht aus zu wissen, dass die direkte Arbeit mit dem Speicher gefährlich ist - Sie sollten auch genau verstehen, wie gefährlich dies ist. Ich mag die Metapher "Sich in den Fuß schießen" für all diese Fälle nicht wirklich - oft ist es nicht so, dass Sie den Abzug betätigen, aber oft ist es ein Schauspieler mit Interessen, die Ihren und / oder den Ihrer Benutzer widersprechen .
Wenn Sie beispielsweise in einer Architektur mit absteigendem Stapel (die gängigsten Architekturen passen zu dieser Rechnung - x86 und ARM im Allgemeinen enthalten), wenn Sie eine Funktion aufrufen, wird die Rücksprungadresse für die Funktion nach den in der Liste definierten lokalen Variablen auf dem Stapel abgelegt Körper der Funktion. Wenn Sie also einen Puffer als lokale Variable deklarieren und diese Variable der Außenwelt aussetzen, ohne auf Pufferüberlauf zu prüfen, gehen Sie wie folgt vor:
void myFn(void){char buf[256];
gets(buf);}
Ein externer Benutzer kann Ihnen eine Zeichenfolge senden, die die Rücksprungadresse vom Stapel überschreibt. Grundsätzlich kann er die Laufzeitidee Ihres Programms für das Aufrufdiagramm ändern, das zur aktuellen Funktion führt. Der Benutzer gibt Ihnen also eine Zeichenfolge, die die binäre Darstellung eines ausführbaren Codes für Ihre Architektur darstellt, genügend Auffüllungen, um den Stapel zu überlaufen myFn, und einige zusätzliche Daten, um die Rücksprungadresse zu überschreiben myFn, um auf den Code zu verweisen, den er Ihnen gegeben hat. Wenn dies passiert, myFnverzweigt es normalerweise zu Code, den der böswillige Benutzer bereitgestellt hat , wenn er normalerweise die Kontrolle an seinen Anrufer zurückgegeben hätte. Wenn Sie C- (oder C ++) Code schreiben, der möglicherweise nicht vertrauenswürdigen Benutzern ausgesetzt ist, müssen Sie diesen Angriffsvektor verstehen. Sie sollten verstehen, warum ein Pufferüberlauf gegen den Stapel oft (aber nicht immer) leichter ausgenutzt werden kann als einer gegen den Heap, und Sie sollten verstehen, wie der Speicher im Heap aufgebaut ist (nicht unbedingt zu detailliert, aber der Die Vorstellung, dass eine malloc()Region von Kontrollstrukturen umgeben ist, kann helfen, zu verstehen, warum Ihr Programm in einer anderen malloc()oder in einer anderen abstürzt free().
C macht Sie mit einfachen Details über die Funktionsweise Ihres Computers vertraut und bietet Ihnen eine direktere Kontrolle über Ihren Computer als jede andere vom Benutzer bearbeitete Sprache, die heute weit verbreitet ist. Mit großer Leistung geht eine große Verantwortung einher - Sie müssen diese Details auf niedriger Ebene verstehen, um sicher und effektiv mit C arbeiten zu können.
2 + 2 = 4
Antworten:
Spezifisch für C? Abgesehen von Standardkonstrukten, die den meisten prozeduralen Sprachen gemeinsam sind, muss ich sagen:
quelle
Verstehen Sie Zeiger und Sie werden Computer verstehen.
quelle
Neben der hervorragenden Antwort von Pythonagras
wie man komplizierte Erklärungen schreibt (oder zumindest liest), wie z
char (*(*funcs[4])())[10]
funcs ist ein Array [4] von Zeigern auf eine Funktion, die einen Zeiger auf das Array [10] von char zurückgibt
quelle
quelle
AC-Programmierer sollten ... andere Sprachen kennen! ;-) Es ist immer fruchtbar, Konzepte aus anderen Sprachen verschiedener Paradigmen zu kennen, wie OOP, funktionale Programmierung und so weiter.
Im Ernst, ein Blick auf den verschleierten Programmierwettbewerb macht Spaß und ist seltsamerweise auch eine gute Erfahrung.
quelle
Ich erwähnte "Pufferüberläufe" in einem Kommentar zu Pythagras 'Antwort. Ich sollte wahrscheinlich klarstellen, was ich ein bisschen meinte. In C reicht es nicht aus zu wissen, dass die direkte Arbeit mit dem Speicher gefährlich ist - Sie sollten auch genau verstehen, wie gefährlich dies ist. Ich mag die Metapher "Sich in den Fuß schießen" für all diese Fälle nicht wirklich - oft ist es nicht so, dass Sie den Abzug betätigen, aber oft ist es ein Schauspieler mit Interessen, die Ihren und / oder den Ihrer Benutzer widersprechen .
Wenn Sie beispielsweise in einer Architektur mit absteigendem Stapel (die gängigsten Architekturen passen zu dieser Rechnung - x86 und ARM im Allgemeinen enthalten), wenn Sie eine Funktion aufrufen, wird die Rücksprungadresse für die Funktion nach den in der Liste definierten lokalen Variablen auf dem Stapel abgelegt Körper der Funktion. Wenn Sie also einen Puffer als lokale Variable deklarieren und diese Variable der Außenwelt aussetzen, ohne auf Pufferüberlauf zu prüfen, gehen Sie wie folgt vor:
Ein externer Benutzer kann Ihnen eine Zeichenfolge senden, die die Rücksprungadresse vom Stapel überschreibt. Grundsätzlich kann er die Laufzeitidee Ihres Programms für das Aufrufdiagramm ändern, das zur aktuellen Funktion führt. Der Benutzer gibt Ihnen also eine Zeichenfolge, die die binäre Darstellung eines ausführbaren Codes für Ihre Architektur darstellt, genügend Auffüllungen, um den Stapel zu überlaufen
myFn
, und einige zusätzliche Daten, um die Rücksprungadresse zu überschreibenmyFn
, um auf den Code zu verweisen, den er Ihnen gegeben hat. Wenn dies passiert,myFn
verzweigt es normalerweise zu Code, den der böswillige Benutzer bereitgestellt hat , wenn er normalerweise die Kontrolle an seinen Anrufer zurückgegeben hätte. Wenn Sie C- (oder C ++) Code schreiben, der möglicherweise nicht vertrauenswürdigen Benutzern ausgesetzt ist, müssen Sie diesen Angriffsvektor verstehen. Sie sollten verstehen, warum ein Pufferüberlauf gegen den Stapel oft (aber nicht immer) leichter ausgenutzt werden kann als einer gegen den Heap, und Sie sollten verstehen, wie der Speicher im Heap aufgebaut ist (nicht unbedingt zu detailliert, aber der Die Vorstellung, dass einemalloc()
Region von Kontrollstrukturen umgeben ist, kann helfen, zu verstehen, warum Ihr Programm in einer anderenmalloc()
oder in einer anderen abstürztfree()
.C macht Sie mit einfachen Details über die Funktionsweise Ihres Computers vertraut und bietet Ihnen eine direktere Kontrolle über Ihren Computer als jede andere vom Benutzer bearbeitete Sprache, die heute weit verbreitet ist. Mit großer Leistung geht eine große Verantwortung einher - Sie müssen diese Details auf niedriger Ebene verstehen, um sicher und effektiv mit C arbeiten zu können.
quelle
Zusätzlich zu den anderen guten Antworten möchte ich der Liste defensive Programmiertechniken hinzufügen .
Verwenden Sie beispielsweise Asserts am Anfang / Ende von Funktionen, um den Vertrag zu überprüfen.
quelle