Na przykład, SysInternals narzędzie „FileMon” z przeszłości ma sterownik trybu jądra, którego kod źródłowy jest w całości w jednym pliku 4000 linii. To samo dotyczy pierwszego w historii napisanego programu ping (~ 2000 LOC).
Na przykład, SysInternals narzędzie „FileMon” z przeszłości ma sterownik trybu jądra, którego kod źródłowy jest w całości w jednym pliku 4000 linii. To samo dotyczy pierwszego w historii napisanego programu ping (~ 2000 LOC).
Odpowiedzi:
Korzystanie z wielu plików zawsze wymaga dodatkowego obciążenia administracyjnego. Trzeba skonfigurować skrypt kompilacji i / lub plik makefile z oddzielnymi etapami kompilacji i łączenia, upewnić się, że zależności między różnymi plikami są poprawnie zarządzane, napisać skrypt „zip” dla łatwiejszej dystrybucji kodu źródłowego przez e-mail lub do pobrania, i tak dalej na. Współczesne środowiska IDE zwykle obciążają wiele tego obciążenia, ale jestem pewien, że w czasie, gdy napisano pierwszy program ping, takie środowisko IDE nie było dostępne. A w przypadku plików tak małych jak ~ 4000 LOC, bez takiego IDE, które dobrze zarządza wieloma plikami, kompromis między wspomnianym kosztem ogólnym a korzyściami wynikającymi z używania wielu plików może pozwolić ludziom podjąć decyzję o podejściu opartym na jednym pliku.
Ponieważ C nie jest dobry w modularyzacji. Robi się bałagan (pliki nagłówkowe i #include, funkcje zewnętrzne, błędy czasu łącza itp.), A im więcej modułów wprowadzasz, tym trudniej robi się.
Bardziej nowoczesne języki mają po części lepsze możliwości modularyzacji, ponieważ nauczyły się na błędach języka C i ułatwiają podział bazy kodu na mniejsze, prostsze jednostki. Ale w przypadku C korzystne może być uniknięcie lub zminimalizowanie wszystkich tych problemów, nawet jeśli oznacza to zbicie tego, co w innym przypadku byłoby zbyt dużym kodem w jednym pliku.
Oprócz powodów historycznych istnieje jeden powód, aby użyć tego w nowoczesnym oprogramowaniu wrażliwym na wydajność. Gdy cały kod znajduje się w jednej jednostce kompilacyjnej, kompilator może przeprowadzać optymalizacje całego programu. Przy osobnych jednostkach kompilacyjnych kompilator nie może zoptymalizować całego programu w określony sposób (np. Wstawiając określony kod).
Linker z pewnością może wykonać pewne optymalizacje oprócz tego, co potrafi kompilator, ale nie wszystkie. Na przykład: nowoczesne konsolidatory są naprawdę dobre w tworzeniu funkcji, do których nie ma odniesienia, nawet w plikach wielu obiektów. Mogą być w stanie wykonać inne optymalizacje, ale nic podobnego do tego, co kompilator może zrobić wewnątrz funkcji.
Jednym dobrze znanym przykładem modułu kodu z jednym kodem źródłowym jest SQLite. Możesz przeczytać więcej na ten temat na stronie The SQLite Amalgamation .
1. Streszczenie
Ponad 100 oddzielnych plików źródłowych łączy się w pojedyncze duże pliki kodu C o nazwie „sqlite3.c” i nazywane „amalgamacją”. Połączenie zawiera wszystko, czego aplikacja potrzebuje do osadzenia SQLite. Plik połączenia ma ponad 180 000 linii długości i ponad 6 megabajtów.
Połączenie całego kodu SQLite w jeden duży plik ułatwia wdrożenie SQLite - jest tylko jeden plik do śledzenia. A ponieważ cały kod znajduje się w jednej jednostce tłumaczącej, kompilatory mogą przeprowadzić lepszą optymalizację między procedurami, dzięki czemu kod maszynowy jest od 5% do 10% szybszy.
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)
niż przenieść wszystko do jednego pliku soudce. Możesz nawet wykonać kompilację całego programu jako alternatywny cel dla tradycyjnego skryptu kompilacji, który pomija rekompilację plików źródłowych, które nie uległy zmianie, podobnie jak ludzie mogą wyłączyć profilowanie i debugowanie dla celu produkcyjnego. Nie masz tej opcji, jeśli wszystko znajduje się w jednym źródle dużej sterty. Ludzie nie są do tego przyzwyczajeni, ale nie ma w tym nic uciążliwego.
Oprócz czynnika prostoty, o którym wspomniał drugi respondent, wiele programów w języku C jest napisanych przez jedną osobę.
Gdy masz zespół osób, pożądane jest podzielenie aplikacji na kilka plików źródłowych, aby uniknąć nieuzasadnionych konfliktów w zmianach kodu. Zwłaszcza, gdy w projekcie pracują zarówno zaawansowani, jak i bardzo młodsi programiści.
Gdy jedna osoba pracuje sama, nie stanowi to problemu.
Osobiście używam wielu plików w zależności od funkcji jako zwyczajowej rzeczy. Ale to tylko ja.
Ponieważ C89 nie miał inline
funkcji. Co oznaczało, że rozbicie pliku na funkcje spowodowało narzut związany z wypychaniem wartości na stos i przeskakiwaniem. To dodało sporo narzutu związanego z implementacją kodu w 1 dużej instrukcji switch (pętla zdarzeń). Ale pętla zdarzeń jest zawsze o wiele trudniejsza do wydajnego (lub nawet poprawnego) wdrożenia niż rozwiązanie bardziej modułowe. Dlatego w przypadku dużych projektów ludzie nadal decydują się na modułowość. Ale kiedy mieli przemyślany projekt z wyprzedzeniem i mogli kontrolować stan w instrukcji 1 przełącznika, zdecydowali się na to.
W dzisiejszych czasach, nawet w C, nie trzeba poświęcać wydajności w celu modularyzacji, ponieważ nawet w funkcjach C można wprowadzić.
inline
słowa kluczowego w kompilatorach C89, nie mogło być inline, dlatego właśnie trzeba było napisać wszystko w jednej gigantycznej funkcji. Prawie nigdy nie powinieneś używać inline
jako optymalizacji wydajności - kompilator i tak będzie wiedział lepiej niż ty (i równie dobrze może zignorować słowo kluczowe).
inline
kluczowe ma semantykę związaną z linkerem, która jest ważniejsza niż pytanie, czy należy przeprowadzać optymalizacje w linii, ale niektóre implementacje mają inne dyrektywy kontrolujące wstawianie i takie rzeczy mogą czasami być bardzo ważne. W niektórych przypadkach funkcja może wyglądać, jakby była zbyt duża, aby była warta wstawienia, ale ciągłe składanie może skrócić rozmiar i czas wykonania prawie do zera. Kompilator, który nie ma silnego nacisku, aby zachęcić do
To liczy się jako przykład ewolucji, co mnie dziwi, nie zostało jeszcze wspomniane.
W ciemnych czasach programowania kompilacja jednego PLIKU może zająć minuty. Jeśli program został zmodularyzowany, wówczas dołączenie niezbędnych plików nagłówkowych (brak wstępnie skompilowanych opcji nagłówka) stanowiłoby znaczącą dodatkową przyczynę spowolnienia. Dodatkowo kompilator może wybrać / wymagać przechowywania niektórych informacji na samym dysku, prawdopodobnie bez korzyści z automatycznego pliku wymiany.
Zwyczaje, które te czynniki środowiskowe przełożyły na ciągłe praktyki rozwojowe i z czasem powoli się dostosowywały.
W tym czasie zysk z korzystania z jednego pliku byłby podobny do tego, jaki uzyskujemy dzięki zastosowaniu dysków SSD zamiast dysków HDD.