Przeczytaj SICP i poznaj schemat oraz praktyczną ideę abstrakcyjnych typów danych . Zatem kodowanie w C jest łatwe (ponieważ z SICP, trochę C, trochę PHP, Ruby itp. ... twoje myślenie byłoby wystarczająco poszerzone i zrozumiałbyś, że programowanie obiektowe może nie być najlepszym stylem w wszystkie przypadki, ale tylko w przypadku niektórych programów). Uważaj na dynamiczną alokację pamięci C , która jest prawdopodobnie najtrudniejszą częścią. C99 lub C11 standardowy język programowania, a jej Biblioteka standardowa języka C jest rzeczywiście dość słaba (nie wiem o TCP lub katalogów!), I będziesz często potrzebować zewnętrznych bibliotek lub interfejsów (npPOSIX , libcurl dla biblioteki klienta HTTP, libonion dla biblioteki serwera HTTP, GMPlib dla bignums, niektóre biblioteki takie jak libunistring dla UTF-8 itp.).
Twoje „obiekty” często znajdują się w C niektórych pokrewnych structi definiujesz zestaw funkcji, które na nich działają. W przypadku krótkich lub bardzo prostych funkcji rozważ ich zdefiniowanie za pomocą odpowiedniego struct, jak static inlinew niektórych plikach nagłówkowych, które foo.hmają być #include-d gdzie indziej.
Zauważ, że programowanie obiektowe nie jest jedynym paradygmatem programowania . W niektórych przypadkach warto zastosować inne paradygmaty ( programowanie funkcjonalne à la Ocaml lub Haskell, a nawet Scheme lub Commmon Lisp, programowanie logiczne à la Prolog itp. Itd. ... Przeczytaj także blog J.Pitrat o deklaratywnej sztucznej inteligencji). Zobacz książkę Scotta: Programming Language Pragmatics
W rzeczywistości programista w C lub Ocaml zwykle nie chce kodować w obiektowym stylu programowania. Nie ma powodu, aby zmuszać się do myślenia o przedmiotach, gdy nie jest to przydatne.
Zdefiniujesz niektóre structi działające na nich funkcje (często przez wskaźniki). Możesz potrzebować niektórych oznaczonych związków (często structze znacznikiem, często niektórych enumi niektórych unionwewnątrz), a może być przydatne posiadanie elastycznego elementu tablicy na końcu niektórych struct-s.
Zajrzyj do kodu źródłowego istniejącego wolnego oprogramowania w C (
aby znaleźć trochę, zobacz github i sourceforge ). Prawdopodobnie przydatna byłaby instalacja i używanie dystrybucji Linuksa: jest ona zbudowana prawie wyłącznie z wolnego oprogramowania, ma świetne kompilatory C wolnego oprogramowania ( GCC , Clang / LLVM ) i narzędzia programistyczne. Zobacz także Zaawansowane programowanie w systemie Linux, jeśli chcesz programować dla systemu Linux.
Nie zapomnij skompilować z wszystkich ostrzeżeń i informacji debugowania, np gcc -Wall -Wextra -g-notably trakcie rozwoju i debugowania phases- i nauczyć się korzystać z pewnych narzędzi, np Valgrind na polowanie wycieki pamięci , do gdbdebuggera itp Zadbaj, aby zrozumieć dobrze, co jest niezdefiniowane zachowanie i mocno go uniknąć (należy pamiętać, że program może mieć jakiś UB i czasami wydaje się „praca”).
Gdy naprawdę potrzebujesz konstrukcji obiektowych (w szczególności dziedziczenia ), możesz użyć wskaźników do powiązanych struktur i funkcji. Możesz mieć własną maszynę vtable , mieć każdy „obiekt” zaczynający się od wskaźnika do structzawierających wskaźniki funkcji. Korzystasz z możliwości rzutowania typu wskaźnika na inny typ wskaźnika (oraz z faktu, że możesz rzutować z struct super_stpola zawierającego te same typy pól, co te rozpoczynające się struct sub_stna emulacji dziedziczenia). Zauważ, że C wystarcza do zaimplementowania dość wyrafinowanych systemów obiektowych - w szczególności przestrzegając pewnych konwencji - jak pokazuje GObject (z GTK / Gnome).
Kiedy rzeczywiście trzeba zamknięć , będziesz często naśladować ich wywołania zwrotne , z konwencją , że każda funkcja przy użyciu wywołania zwrotnego jest przekazywana zarówno wskaźnik funkcji i niektóre dane klienta (zużywanej przez wskaźnik funkcji, gdy nazywa to). Możesz także (konwencjonalnie) mieć swoje własne zamknięcia struct(zawierające pewien wskaźnik funkcji i wartości zamknięte).
Ponieważ C jest językiem bardzo niskiego poziomu, ważne jest, aby zdefiniować i udokumentować własne konwencje (inspirowane praktyką w innych programach C), w szczególności dotyczące zarządzania pamięcią i prawdopodobnie także niektórych konwencji nazewnictwa. Przydaje się pomysł na architekturę zestawu instrukcji . Nie zapominaj, że C kompilator może zrobić wiele optymalizacje na kodzie (jeśli zapytać go do), więc nie obchodzi zbytnio robi mikro optymalizacje ręcznie, zostawiam to do kompilatora ( dla optymalnego zestawienia zwolniony oprogramowanie). Jeśli zależy Ci na testach porównawczych i wydajności, powinieneś włączyć optymalizacje (po debugowaniu programu).gcc -Wall -O2
Nie zapominaj, że czasami metaprogramowanie jest przydatne . Dość często duże oprogramowanie napisane w C zawiera skrypty lub programy ad-hoc do generowania kodu C używanego gdzie indziej (możesz także grać w brudne sztuczki preprocesora C , np. Makra X ). Istnieje kilka przydatnych generatorów programów C (np. Yacc lub gnu bison do generowania parserów, gperf do generowania doskonałych funkcji skrótu itp.). W niektórych systemach (zwłaszcza Linux i POSIX) możesz nawet wygenerować kod C w czasie wykonywania w generated-001.cpliku, skompilować go do współdzielonego obiektu, uruchamiając komendę (np. gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so) W czasie wykonywania, dynamicznie ładować ten obiekt współdzielony za pomocą dlopeni pobierz wskaźnik funkcji z nazwy za pomocą dlsym . Robię takie sztuczki w MELT (język specyficzny dla domeny Lisp, który może ci się przydać, ponieważ umożliwia dostosowanie kompilatora GCC ).
Pamiętaj o koncepcjach i technikach odśmiecania pamięci ( zliczanie referencji jest często techniką zarządzania pamięcią w C, a IMHO jest słabą formą odśmiecania, która nie radzi sobie dobrze z referencjami cyklicznymi ; możesz mieć słabe wskaźniki, które mogą w tym pomóc ale może to być trudne). Czasami możesz rozważyć użycie konserwatywnego urządzenia do usuwania śmieci Boehm .
qux = foo.bar(baz)stają sięqux = Foo_bar(foo, baz).