2013-03-27 15 views
9

Jakie są praktyczne różnice między używaniem modułów a instrukcją use lub pojedyncze pliki z instrukcją include? Mam na myśli, jeśli mam podprogram, który jest często używany w całym programie: kiedy lub dlaczego powinienem umieścić go w module lub po prostu napisać go w osobnym pliku i umieścić go w każdej innej części programu, gdzie musi być używany?Różnica między INCLUDE i modułami w Fortranie

Czy dobrze byłoby napisać wszystkie podprogramy przeznaczone do umieszczenia w module w osobnych plikach i użyć wewnątrz modułu include? Zwłaszcza, jeśli kod w podprogramach jest długi, tak aby kod był lepiej zorganizowany (w ten sposób wszystkie podprogramy są spakowane w mod, ale jeśli muszę je edytować, nie muszę przechodzić przez labirynt kodu).

Odpowiedz

16

Różnice koncepcyjne między dwiema mapami aż do bardzo istotnych różnic praktycznych.

Linia ZAWIERA działa na poziomie źródłowym - dokonuje prostego ("niemego") wpisywania tekstu. W przypadku braku jakiejkolwiek specjalnej interpretacji procesora "pliku" (nie wymagającego, aby faktycznie był to plik) w linii włączania, całe źródło może dość łatwo zostać splicowane razem przez programistę i podane do kompilatora bez żadnej różnicy - zawsze w semantyce źródła. Dołączone źródło nie ma żadnej interpretacji w izolacji - jego znaczenie jest całkowicie zależne od kontekstu, w którym pojawia się linia dołączająca, która odwołuje się do zawartego źródła.

Moduły działają na znacznie wyższym poziomie encji programu, tj. Na poziomie, na którym kompilator rozważa rzeczy, które faktycznie opisuje źródło. Moduł można skompilować w izolacji od dalszych użytkowników i po skompilowaniu kompilator dokładnie wie, jakie elementy moduł może dostarczyć programowi.

Zazwyczaj co ktoś używając obejmują linie jest nadzieję zrobić to, co było faktycznie moduły zaprojektowane zrobić.

Przykładowe zagadnienia:

  • Ponieważ deklaracje jednostka może być rozłożona na wiele instrukcji opisane przez podmioty włączone źródła nie może być to, czego oczekują. Rozważmy następujący źródło, które należy uwzględnić:

    INTEGER :: i

    W izolacji wygląda to tak deklaruje nazwę i jako skalara całkowitej (albo funkcja kto wie?!). Teraz rozważmy następujący zakres, który obejmuje wyżej:

    INCLUDE "source from above"
    DIMENSION :: i(10,10)

    i jest postój dwóch tablicy! Być może chcesz, aby był to POINTER? PRZYKŁADOWA? Fałszywy argument? Być może to powoduje błąd, a może jest to prawidłowe źródło! Rzuć niejawne wpisywanie w miks, aby naprawdę zwiększyć potencjalną zabawę.

    Jednostka definiowana w module jest "całkowicie" definiowana przez moduł. Atrybuty specyficzne dla zakresu zastosowania mogą zostać zmienione (LOTNOŚĆ, dostępność itd.), Ale podstawowa jednostka pozostaje taka sama. Zderzenia nazw są jawnie wywoływane i można je łatwo obejść przy użyciu klauzuli zmiany nazwy w instrukcji USE.

  • Fortran ma ograniczenia dotyczące zamawiania instrukcji (wyciągi specyfikacji muszą występować przed instrukcjami wykonywalnymi itp.). Dołączone źródło podlega również tym ograniczeniom, ponownie w kontekście punktu włączenia, a nie punktu definicji źródła.

    Dobrze wymieszaj z niejednoznacznością źródła między definicjami funkcji instrukcji (część specyfikacji) i instrukcjami przypisania (część wykonywalna) dla niektórych całkowicie rozwlekłych komunikatów o błędach lub, co gorsza, cichej akceptacji przez kompilator błędnego kodu.

    Istnieją wymagania dotyczące miejsca, w którym pojawia się instrukcja USE odnosząca się do modułu, ale źródło dla rzeczywistej jednostki programu modułu jest całkowicie niezależne od punktu użycia.

  • Masz ochotę na jakiś globalny stan, który chcesz udostępnić w powiązanych procedurach i chcesz go wykorzystać? Pozwól, że przedstawię Ci wspólne bloki i związaną z nimi koncepcję skojarzeń sekwencji ...

    Powiązanie sekwencji jest niefortunnym krwawieniem z wczesnej implementacji bazowej implementacji Fortran, która jest podatnym na błędy, nieelastycznym anachronizmem anty-optymalizacyjnym.

    Zmienne modułu powodują, że wspólne bloki i związane z nimi zło są zupełnie niepotrzebne.

  • Jeśli korzystasz z linii włączania, to zauważ, że nie dodajesz źródła często używanej procedury (sugestia w twoim pierwszym akapicie spowoduje tylko marnotrawienie błędów składniowych kompilatora) . Typowe czynności obejmują źródło opisujące procedurę. W przypadku każdej nietrywialnej procedury źródło opisujące interfejs różni się od pełnego źródła procedury - co oznacza, że ​​trzeba teraz zachować dwie reprezentacje źródłowe tej samej rzeczy. Jest to obciążenie podatne na błędy.

    Jak wspomniano - kompilatory automatycznie zyskują wiedzę na temat interfejsu procedury modułu (wiedza na temat kompilatora jest "jawna", ponieważ faktycznie zobaczyła kod procedury - stąd określenie "jawny interfejs"). Nie ma potrzeby, aby programista robił cokolwiek więcej.

    Konsekwencją powyższego jest to, że podprogramy zewnętrzne nie powinny być stosowane na wszystkich chyba są bardzo dobre powody do przeciwnie (chyba istnienie okrągłych lub nadmiernie rozbudowanych zależnościami) - podstawowy punkt wyjścia powinno być, aby umieścić wszystko w module lub programie głównym.

Inne plakaty wspomnieli kod źródłowy korzyści organizacyjne modułów - w tym zdolność do grupowania powiązanych procedur i inne „rzeczy” w jednym pakiecie, kontrolę nad dostępnością wewnętrznych szczegółów implementacji.

Przyjmuję, że istnieje prawidłowe użycie INCLUDE linii zgodnie z drugim akapitem pytania - gdzie duże moduły stają się nieporęczne pod względem wielkości. F2008 rozwiązał ten problem dzięki submodułom, które przynoszą także szereg innych korzyści. Po uzyskaniu szerokiego poparcia należy zaniechać prac nad włączaniem linii.

Drugim ważnym zastosowaniem jest przezwyciężenie braku wsparcia przez język dla ogólnych technik programowania (jakie szablony zapewniają w C++) - tj. Gdzie typy obiektów uczestniczących w operacji mogą się różnić, ale sekwencja tokena opisująca, co zrobić na tych obiektach jest zasadniczo taki sam. Może minie jeszcze jakieś dziesięć lat, zanim język to rozwiąże.

+0

Więc nie ma wad w oddzielaniu podprogramów w różnych plikach, a następnie za pomocą dołączania wewnątrz modułu, prawda? Nigdy wcześniej nie słyszałem o submodułach. – Nordico

+1

Zastanowiłbym się tylko, czy mam bardzo duże pliki źródłowe lub jako część starszej migracji źródeł. Jeśli to możliwe, najpierw rozważałbym podzielenie modułu na kilka modułów "potomnych", które następnie są agregowane razem z instrukcjami USE w module nadrzędnym. Jednak przy skomplikowanych zależnościach typu/procedur i/lub ze sposobem, w jaki działa dostępność PUBLIC/PRIVATE firmy Fortran, używanie modułów potomnych może nie zawsze być możliwe. Może się okazać, że zszywanie źródła dla modułu razem z liniami INCLUDE powoduje dezorientację niektórych systemów kompilacji. – IanH

6

Umieszczanie procedur w modułach i używanie tych modułów czyni jawny interfejs procedury. Pozwala kompilatorowi Fortran sprawdzić spójność między faktycznymi argumentami w wywołaniu i fałszywymi argumentami procedury. Chroni przed różnymi błędami programistów. Wyraźny interfejs jest również niezbędny w przypadku niektórych "zaawansowanych" funkcji Fortran> = 90; na przykład argumenty opcjonalne lub słowa kluczowe. Bez jawnego interfejsu kompilator nie wygeneruje poprawnego połączenia. Samo dołączenie pliku nie zapewnia tych zalet.

+1

Poszedłbym dalej, nie sądzę, że istnieją dobre powody, by używać plików włączających. –

+0

@HighPerformanceMark: Ogólne programowanie dla biednego człowieka? – eriktous

+1

Tak jak napisałem * nie znam żadnych dobrych powodów, aby używać plików include *. Ale jest to opinia –

3

Odpowiedź M.S.B. jest świetna i jest prawdopodobnie najważniejszym powodem, dla którego warto preferować moduły. Chciałbym dodać jeszcze kilka myśli.

Korzystanie z modułów zmniejsza skompilowany rozmiar binarny, jeśli jest to dla Ciebie ważne. Moduł jest skompilowany jeden raz, a kiedy jesteś use, symbolicznie ładujesz ten moduł, aby użyć kodu. Kiedy jesteś plikiem include, faktycznie wstawiasz nowy kod do swojej procedury. Jeśli użyjesz include, może to spowodować, że twój plik binarny będzie duży, a także zwiększy czas kompilacji.

Możesz również użyć modułów do udawania kodowania stylu OOP w Fortran 90 poprzez sprytne użycie funkcji publicznych i prywatnych oraz typów zdefiniowanych przez użytkownika w module. Nawet jeśli nie chcesz tego robić, zapewnia to dobry sposób grupowania funkcji, które logicznie należą do siebie.

Powiązane problemy