Lesen Sie SICP und lernen Sie Schema und die praktische Idee der abstrakten Datentypen . Dann ist das Codieren in C einfach (da mit SICP, ein bisschen C und ein bisschen PHP, Ruby usw. Ihre Überlegungen erweitert würden und Sie verstehen würden, dass objektorientierte Programmierung möglicherweise nicht der beste Stil in C ist in allen Fällen, aber nur für bestimmte Programme). Seien Sie vorsichtig mit der dynamischen Speicherzuweisung in C , was wahrscheinlich der schwierigste Teil ist. Der Programmiersprachenstandard C99 oder C11 und seine C-Standardbibliothek sind eigentlich ziemlich schlecht (TCP oder Verzeichnisse sind ihm nicht bekannt!), Und Sie benötigen häufig einige externe Bibliotheken oder Schnittstellen (z. B.POSIX , libcurl für die HTTP-Client-Bibliothek, libonion für die HTTP-Server-Bibliothek, GMPlib für Bignums, einige Bibliotheken wie libunistring für UTF-8 usw.).
Ihre "Objekte" sind häufig in C verwandte struct
-s, und Sie definieren die Menge der Funktionen, die auf sie angewendet werden. Für kurze oder sehr einfache Funktionen sollten Sie sie mit der entsprechenden Definition struct
wie static inline
in einer Header-Datei definieren foo.h
, die an #include
anderer Stelle eingefügt werden soll.
Beachten Sie, dass objektorientierte Programmierung nicht das einzige Programmierparadigma ist . In einigen Fällen lohnen sich andere Paradigmen ( funktionale Programmierung à la Ocaml oder Haskell oder sogar Schema oder Commmon Lisp, logische Programmierung à la Prolog usw. usw.). Lesen Sie auch J.Pitrats Blog über deklarative künstliche Intelligenz. Siehe Scotts Buch: Programming Language Pragmatics
Tatsächlich möchte ein Programmierer in C oder Ocaml normalerweise nicht in einem objektorientierten Programmierstil programmieren. Es gibt keinen Grund, sich dazu zu zwingen, an Gegenstände zu denken, wenn dies nicht nützlich ist.
Sie definieren einige struct
und die Funktionen, die auf ihnen ausgeführt werden (häufig durch Zeiger). Möglicherweise benötigen Sie einige getaggte Gewerkschaften (häufig eine struct
mit einem Tag-Mitglied, häufig einige enum
und einige im union
Inneren), und möglicherweise ist es hilfreich, am Ende einiger Ihrer -s ein flexibles Array-Mitglied zu haben struct
.
Schauen Sie sich den Quellcode einiger freier Software in C an (siehe github & sourceforge
, um einige zu finden). Wahrscheinlich wäre die Installation und Verwendung einer Linux-Distribution nützlich: Sie besteht fast nur aus freier Software, enthält großartige C-Compiler für freie Software ( GCC , Clang / LLVM ) und Entwicklungstools. Siehe auch Erweiterte Linux-Programmierung, wenn Sie für Linux entwickeln möchten.
Vergessen Sie nicht , mit allen Warnungen und Debug - Informationen, zum Beispiel zu kompilieren gcc -Wall -Wextra -g
-notably bei der Entwicklung und Debugging phases- und lernen einige Werkzeuge zu verwenden, zB valgrind zu jagen Speicherlecks , der gdb
Debugger usw. Achten Sie auf gut zu verstehen , was nicht definiert Verhalten und stark vermeiden Sie es (denken Sie daran, dass ein Programm einige UB haben könnte und manchmal zu "arbeiten" scheint).
Wenn Sie wirklich objektorientierte Konstrukte (insbesondere Vererbung ) benötigen , können Sie Zeiger auf verwandte Strukturen und auf Funktionen verwenden. Sie könnten Ihre eigene vtable- Maschinerie haben, wobei jedes "Objekt" mit einem Zeiger auf einen struct
enthaltenden Funktionszeiger beginnt . Sie profitieren von der Möglichkeit, einen Zeigertyp in einen anderen Zeigertyp umzuwandeln (und von der Tatsache, dass Sie einen struct super_st
Zeigertyp umwandeln können , der dieselben Feldtypen enthält wie diejenigen, die mit a beginnen struct sub_st
, um die Vererbung zu emulieren). Beachten Sie, dass C ausreicht, um ziemlich ausgefeilte Objektsysteme zu implementieren - insbesondere unter Einhaltung einiger Konventionen -, wie GObject (von GTK / Gnome) demonstriert.
Wenn Sie wirklich brauchen , Verschlüsse , werden Sie oft emulieren sie mit Rückrufen , mit der Konvention , dass jede Funktion eines Rückruf mit beiden Zeigern einer Funktion übergeben wird und einige Client - Daten (von dem Funktionszeiger verbraucht wird, wenn es das nennt). Sie könnten auch (konventionell) Ihre eigenen schließungsähnlichen struct
-s haben (die einen Funktionszeiger und die geschlossenen Werte enthalten).
Da C eine sehr einfache Sprache ist, ist es wichtig, eigene Konventionen zu definieren und zu dokumentieren (inspiriert von der Praxis in anderen C-Programmen), insbesondere in Bezug auf die Speicherverwaltung und möglicherweise auch einige Namenskonventionen. Es ist nützlich, eine Vorstellung von der Befehlssatzarchitektur zu haben . Vergessen Sie nicht, dass ein C- Compiler möglicherweise viele Optimierungen an Ihrem Code vornimmt (wenn Sie ihn dazu auffordern). Überlassen Sie die Mikrooptimierung also Ihrem Compiler ( gcc -Wall -O2
für eine optimierte Kompilierung der veröffentlichten Versionen) Software). Wenn Sie sich für Benchmarking und Raw-Leistung interessieren, sollten Sie Optimierungen aktivieren (sobald Ihr Programm debuggt wurde).
Vergessen Sie nicht, dass Metaprogrammierung manchmal nützlich ist . In C geschriebene große Software enthält häufig Skripte oder Ad-hoc-Programme, um C-Code zu generieren, der an anderer Stelle verwendet wird (und möglicherweise spielen Sie auch einige schmutzige C-Präprozessor- Tricks ab, z. B. X-Makros ). Es gibt einige nützliche C-Programmgeneratoren (z. B. yacc oder gnu bison zum Generieren von Parsern, gperf zum Generieren perfekter Hash-Funktionen usw.). Auf einigen Systemen (insbesondere Linux und POSIX) können Sie sogar zur Laufzeit C-Code in einer generated-001.c
Datei generieren , ihn zu einem gemeinsam genutzten Objekt kompilieren, indem Sie zur Laufzeit einen Befehl (z. B. gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) ausführen und dieses gemeinsam genutzte Objekt dynamisch mit dlopen laden& Mit dlsym einen Funktionszeiger von einem Namen abrufen . Ich mache solche Tricks in MELT (eine Lisp-ähnliche domänenspezifische Sprache, die für Sie nützlich sein könnte, da sie die Anpassung des GCC- Compilers ermöglicht).
Seien Sie sich bewusst von der Garbage Collection Konzepte und Techniken ( Referenzzählung ist oft eine Technik zu verwalten Speicher in C, und es ist meiner Meinung nach eine schlechte Form der Garbage Collection , die nicht gut behandeln zirkuläre Referenzen , Sie haben könnten schwache Zeiger zu helfen darüber, aber es könnte schwierig sein). In einigen Fällen könnten Sie in Betracht ziehen, den konservativen Müllmann von Boehm zu verwenden .
qux = foo.bar(baz)
zuqux = Foo_bar(foo, baz)
.