Mam niewiele więcej niż umiejętności na poziomie C na poziomie początkującym i chciałbym wiedzieć, czy istnieją jakieś „standardy” dotyczące struktury nieco złożonej aplikacji w języku C. Nawet te oparte na GUI.
Zawsze korzystałem z paradygmatu OO w Javie i PHP, a teraz, gdy chcę się uczyć C, obawiam się, że mogę źle ukształtować moje aplikacje. Nie mam pojęcia, które wytyczne należy przestrzegać, aby mieć modułowość, oddzielenie i suchość w języku proceduralnym.
Czy masz jakieś sugestie do czytania? Nie mogłem znaleźć żadnego frameworka aplikacji dla C, nawet jeśli nie używam frameworków, zawsze znajdowałem fajne pomysły, przeglądając ich kod.
c
project-management
Stephen
źródło
źródło
Odpowiedzi:
Kluczem jest modułowość. Jest to łatwiejsze do zaprojektowania, wdrożenia, kompilacji i utrzymania.
Jeśli masz czas na naukę, zobacz, jak zbudowana jest aplikacja Ada, z jej obowiązkiem
package
(interfejs modułu) ipackage body
(implementacją modułu).To jest do kodowania.
W celu utrzymania (pamiętaj, że kodujesz raz, ale konserwujesz kilka razy) proponuję udokumentować swój kod; Doxygen to dla mnie fajny wybór. Proponuję również zbudowanie mocnego zestawu testów regresji, który umożliwia refaktoryzację.
źródło
Powszechnym błędem jest przekonanie, że techniki OO nie mogą być stosowane w C. Większość tak - po prostu są one nieco bardziej nieporęczne niż w językach ze składnią dedykowaną do tego zadania.
Jedną z podstaw solidnego projektu systemu jest hermetyzacja implementacji za interfejsem.
FILE*
i funkcje, że praca z nim (fopen()
,fread()
etc.) jest przykładem na to, jak dobry enkapsulacji może być stosowany w C ustanowienie interfejsów. (Oczywiście, ponieważ C nie ma specyfikatorów dostępu, nie można wymusić, aby nikt nie zaglądał do wnętrza astruct FILE
, ale zrobiłby to tylko masochista).Jeśli to konieczne, zachowanie polimorficzne można uzyskać w C za pomocą tabel wskaźników funkcji. Tak, składnia jest brzydka, ale efekt jest taki sam jak funkcji wirtualnych:
struct IAnimal { int (*eat)(int food); int (*sleep)(int secs); }; /* "Subclass"/"implement" IAnimal, relying on C's guaranteed equivalence * of memory layouts */ struct Cat { struct IAnimal _base; int (*meow)(void); }; int cat_eat(int food) { ... } int cat_sleep(int secs) { ... } int cat_meow(void) { ... } /* "Constructor" */ struct Cat* CreateACat(void) { struct Cat* x = (Cat*) malloc(sizeof (struct Cat)); x->_base.eat = cat_eat; x->_base.sleep = cat_sleep; x->meow = cat_meow; } struct IAnimal* pa = CreateACat(); pa->eat(42); /* Calls cat_eat() */ ((struct Cat*) pa)->meow(); /* "Downcast" */
źródło
Wszystkie dobre odpowiedzi.
Dodałbym tylko „zminimalizuj strukturę danych”. Może to być nawet łatwiejsze w C, ponieważ jeśli C ++ to „C z klasami”, OOP próbuje zachęcić cię do wzięcia każdego rzeczownika / czasownika w twojej głowie i przekształcenia go w klasę / metodę. To może być bardzo marnotrawne.
Na przykład załóżmy, że masz tablicę odczytów temperatury w punktach w czasie i chcesz wyświetlić je jako wykres liniowy w systemie Windows. Windows ma komunikat PAINT, a kiedy go otrzymasz, możesz zapętlić tablicę wykonując funkcje LineTo, skalując dane w miarę przechodzenia, aby przekonwertować je na współrzędne pikseli.
Zbyt wiele razy widziałem to, że ponieważ wykres składa się z punktów i linii, ludzie zbudują strukturę danych składającą się z obiektów punktowych i obiektów liniowych, z których każdy jest w stanie DrawMyself, a następnie uczynią to trwałym, opierając się na teorii, że jest w jakiś sposób „bardziej wydajne” lub że być może będą musieli umieć przesuwać kursor myszy nad częściami wykresu i wyświetlać dane numerycznie, więc wbudowują metody w obiekty, aby sobie z tym poradzić, i oczywiście polega na tworzeniu i usuwaniu jeszcze większej liczby obiektów.
W efekcie otrzymujesz ogromną ilość kodu, który jest bardzo czytelny i spędza tylko 90% czasu na zarządzaniu obiektami.
Wszystko to odbywa się w imię „dobrej praktyki programistycznej” i „wydajności”.
Przynajmniej w C prosty, skuteczny sposób będzie bardziej oczywisty, a pokusa budowania piramid słabsza.
źródło
Standardy kodowania GNU ewoluowały przez kilka dekad. Dobrze byłoby je przeczytać, nawet jeśli nie przestrzegasz ich co do joty. Myślenie o podniesionych w nich punktach daje ci solidniejszą podstawę do tego, jak skonstruować własny kod.
źródło
Jeśli wiesz, jak uporządkować swój kod w Javie lub C ++, możesz przestrzegać tych samych zasad w przypadku kodu C. Jedyną różnicą jest to, że nie masz po swojej stronie kompilatora i musisz robić wszystko bardzo ostrożnie ręcznie.
Ponieważ nie ma pakietów i klas, musisz zacząć od uważnego zaprojektowania swoich modułów. Najpopularniejszym podejściem jest utworzenie oddzielnego folderu źródłowego dla każdego modułu. Aby rozróżnić kod między różnymi modułami, musisz polegać na konwencjach nazewnictwa. Na przykład poprzedz wszystkie funkcje nazwą modułu.
Nie możesz mieć klas w C, ale możesz łatwo zaimplementować „Abstrakcyjne typy danych”. Tworzysz plik .C i .H dla każdego abstrakcyjnego typu danych. Jeśli wolisz, możesz mieć dwa pliki nagłówkowe, jeden publiczny i jeden prywatny. Chodzi o to, że wszystkie struktury, stałe i funkcje, które mają zostać wyeksportowane, trafiają do publicznego pliku nagłówkowego.
Twoje narzędzia są również bardzo ważne. Przydatnym narzędziem dla C są kłaczki , które mogą pomóc Ci znaleźć nieprzyjemne zapachy w kodzie. Innym narzędziem, którego możesz użyć, jest Doxygen, które może pomóc w generowaniu dokumentacji .
źródło
Hermetyzacja jest zawsze kluczem do pomyślnego rozwoju, niezależnie od języka programowania.
Sztuczka, której użyłem, aby pomóc hermetyzować „prywatne” metody w C, polega na tym, że nie należy umieszczać ich prototypów w pliku „.h”.
źródło
Zasugerowałbym Ci sprawdzenie kodu dowolnego popularnego projektu C open source, takiego jak… hmm… jądro Linuksa lub Git; i zobacz, jak to zorganizują.
źródło
Reguła liczbowa dla złożonych zastosowań: powinna być łatwa do odczytania.
Aby uprościć złożone aplikacje, używam Divide and Conquer .
źródło
Sugerowałbym przeczytanie podręcznika C / C ++ jako pierwszy krok. Na przykład C Primer Plus jest dobrym odniesieniem. Przejrzenie przykładów da ci pomysł, jak zmapować twoją OO java na bardziej proceduralny język, taki jak C.
źródło