Czytałem, że podczas korzystania z programu istnieje pewna optymalizacja kompilatora, #pragma once
która może spowodować szybszą kompilację. Rozumiem, że jest to niestandardowe, a zatem może powodować problem ze zgodnością między platformami.
Czy jest to obsługiwane przez większość nowoczesnych kompilatorów na platformach innych niż Windows (gcc)?
Chcę uniknąć problemów z kompilacją platformy, ale chcę również uniknąć dodatkowej pracy strażników rezerwowych:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
Czy powinienem się martwić? Czy powinienem poświęcić na to więcej energii mentalnej?
c++
include-guards
Ryan Emerle
źródło
źródło
#pragma once
wydaje się, że pozwala uniknąć niektórych problemów z widokiem klas w VS 2008. Właśnie pozbywam się strażników dołączających i zastępuję je z#pragma once
tego powodu.Odpowiedzi:
Używanie
#pragma once
powinno działać na każdym nowoczesnym kompilatorze, ale nie widzę żadnego powodu, aby nie używać standardowej funkcji#ifndef
osłony. Działa dobrze. Jedynym zastrzeżeniem jest to, że GCC nie obsługiwał wersji#pragma once
wcześniejszej niż 3.4 .Przekonałem się również, że przynajmniej w GCC rozpoznaje standard
#ifndef
obejmuje ochronę i optymalizuje ją , więc nie powinna być dużo wolniejsza niż#pragma once
.źródło
#pragma once
jest generalnie szybszy, ponieważ plik nie jest wstępnie przetwarzany.ifndef/define/endif
i tak wymaga wstępnego przetwarzania, ponieważ po tym bloku możesz mieć coś do kompilacji (teoretycznie)#ifndef FOO_BAR_H
zwykle dla pliku takiego jak „foo_bar.h”. Jeśli później zmienisz nazwę tego pliku, czy powinieneś odpowiednio dostosować osłony dołączające, aby były zgodne z tą konwencją? Ponadto, jeśli masz dwa różne foo_bar.h w dwóch różnych miejscach w drzewie kodu, musisz pomyśleć o dwóch różnych symbolach dla każdego z nich. Krótka odpowiedź brzmi:#pragma once
jeśli naprawdę potrzebujesz skompilować w środowisku, które go nie obsługuje, to dodaj i dodaj osłony dla tego środowiska.#pragma once
ma jedną wadę (inną niż niestandardowa), a więc jeśli masz ten sam plik w różnych lokalizacjach (mamy to, ponieważ nasz system kompilacji kopiuje pliki), to kompilator pomyśli, że są to różne pliki.źródło
#ifdef
wartość makra może się również różnić.Chciałbym
#pragma once
(lub coś w tym rodzaju) być w standardzie. Uwzględnij strażników to nie jest wielka sprawa (ale wydaje się, że jest to trochę trudne do wytłumaczenia dla osób uczących się języka), ale wydaje się to niewielką uciążliwością, której można było uniknąć.W rzeczywistości, ponieważ w 99,98% przypadków
#pragma once
zachowanie jest pożądanym zachowaniem, byłoby miło, gdyby kompilator automatycznie obsługiwał wielokrotne włączanie nagłówka za pomocą#pragma
coś” lub „coś”.Ale mamy to, co mamy (z wyjątkiem tego, że możesz nie mieć
#pragma once
).źródło
#import
dyrektywa.Nie wiem o żadnych korzyściach z wydajności, ale na pewno działa. Używam go we wszystkich moich projektach C ++ (oczywiście przy użyciu kompilatora MS). Uważam, że jest bardziej skuteczny niż używanie
Wykonuje tę samą pracę i nie zapełnia preprocesora dodatkowymi makrami.
GCC obsługuje
#pragma once
oficjalnie od wersji 3.4 .źródło
GCC obsługuje
#pragma once
od wersji 3.4, patrz http://en.wikipedia.org/wiki/Pragma_once, aby uzyskać dalszą obsługę kompilatora.Wielką zaletą, którą widzę przy użyciu
#pragma once
zamiast włączania strażników, jest unikanie błędów kopiowania / wklejania.Spójrzmy prawdzie w oczy: większość z nas z trudem rozpoczyna tworzenie nowego pliku nagłówka od zera, ale po prostu kopiuje istniejący i modyfikuje go zgodnie z naszymi potrzebami. Znacznie łatwiej jest stworzyć działający szablon, używając
#pragma once
zamiast uwzględniać strażników. Im mniej muszę modyfikować szablon, tym mniej prawdopodobne jest, że popełniam błędy. Posiadanie tego samego zabezpieczenia w różnych plikach prowadzi do dziwnych błędów kompilatora i zajmuje trochę czasu, aby dowiedzieć się, co poszło nie tak.TL; DR:
#pragma once
jest łatwiejszy w użyciu.źródło
Używam go i jestem z niego zadowolony, ponieważ muszę pisać znacznie mniej, aby utworzyć nowy nagłówek. Działa mi dobrze na trzech platformach: Windows, Mac i Linux.
Nie mam żadnych informacji o wydajności, ale wierzę, że różnica między #pragma i wartownikiem dołączającym nie będzie niczym w porównaniu z powolnością analizowania gramatyki C ++. To jest prawdziwy problem. Spróbuj na przykład skompilować tę samą liczbę plików i linii za pomocą kompilatora C #, aby zobaczyć różnicę.
W końcu użycie strażnika lub pragmy nie będzie miało żadnego znaczenia.
źródło
Użycie „
#pragma once
” może nie przynieść żadnego efektu (nie jest obsługiwane wszędzie - chociaż jest coraz częściej obsługiwane), więc i tak musisz użyć kodu kompilacji warunkowej, w takim przypadku, po co zawracać sobie głowę „#pragma once
”? Kompilator prawdopodobnie i tak go zoptymalizuje. Zależy to jednak od twoich platform docelowych. Jeśli wszystkie twoje cele go obsługują, to idź dalej i skorzystaj z niego - ale powinna to być świadoma decyzja, ponieważ całe piekło rozpęta się, jeśli użyjesz tylko pragmy, a następnie przełączysz się na kompilator, który jej nie obsługuje.źródło
Korzyścią z wydajności jest to, że nie trzeba ponownie otwierać pliku po przeczytaniu #pragmy. W przypadku strażników kompilator musi otworzyć plik (co może być kosztowne w czasie), aby uzyskać informacje, że nie powinien ponownie zawierać jego zawartości.
Jest to teoria tylko dlatego, że niektóre kompilatory nie będą automatycznie otwierać plików, w których nie ma kodu odczytu dla każdej jednostki kompilacji.
W każdym razie nie jest tak w przypadku wszystkich kompilatorów, więc najlepiej #pragma, której należy kiedyś unikać w przypadku kodu wieloplatformowego, nie ma w ogóle standardu / nie ma znormalizowanej definicji i efektu. Jednak praktycznie jest to naprawdę lepsze niż strażnicy.
Ostatecznie lepszym pomysłem na uzyskanie najlepszej prędkości kompilatora bez konieczności sprawdzania zachowania każdego kompilatora w tym przypadku jest użycie zarówno pragmy raz, jak i strażników.
W ten sposób uzyskujesz to, co najlepsze (między platformami i szybkość kompilacji pomocy).
Ponieważ pisanie jest dłuższe, osobiście używam narzędzia, które pomaga wygenerować to wszystko w bardzo złośliwy sposób (Visual Assist X).
źródło
pragma
poifndef
? Czy jest jakaś korzyść?Nie zawsze.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 ma ładny przykład dwóch plików, które mają być uwzględnione, ale błędnie uważane za identyczne z powodu identycznych znaczników czasu i treści (nie identyczna nazwa pliku) .
źródło
#pragma once
jest niestandardowy, więc cokolwiek kompilator zdecyduje się zrobić, jest „poprawne”. Oczywiście wtedy możemy zacząć mówić o tym, co jest „oczekiwane”, a co „przydatne”.Używając gcc 3.4 i 4.1 na bardzo dużych drzewach (czasem korzystających z distcc ), nie widziałem jeszcze żadnego przyspieszenia, gdy używam #pragma zamiast zamiast lub w połączeniu ze standardowymi osłonami.
Naprawdę nie rozumiem, jak warto potencjalnie zagmatwać starsze wersje gcc lub nawet innych kompilatorów, ponieważ nie ma prawdziwych oszczędności. Nie wypróbowałem wszystkich różnych de-linterów, ale jestem gotów się założyć, że wielu z nich się zdezorientuje.
Ja również żałuję, że nie został przyjęty wcześniej, ale widzę argument: „Dlaczego potrzebujemy tego, skoro ifndef działa idealnie?”. Biorąc pod uwagę wiele mrocznych zakątków i złożoności C, osłony to jedna z najłatwiejszych, samo wyjaśniających się rzeczy. Jeśli masz choć niewielką wiedzę na temat działania preprocesora, powinny one być zrozumiałe.
Jeśli zauważysz znaczne przyspieszenie, zaktualizuj swoje pytanie.
źródło
Dzisiaj oldschoolowi strażnicy są tak szybcy, jak kiedyś #pragma. Nawet jeśli kompilator nie traktuje ich specjalnie, zatrzyma się, gdy zobaczy #ifndef WHATEVER i WHATEVER jest zdefiniowane. Otwarcie pliku jest dziś tandetne. Nawet gdyby nastąpiła poprawa, byłaby to rzędu milisekund.
Po prostu nie używam raz #pragmy, ponieważ nie przynosi to żadnych korzyści. Aby uniknąć kolizji z innymi strażnikami, używam czegoś takiego: CI_APP_MODULE_FILE_H -> CI = firmowe inicjały; APP = nazwa aplikacji; reszta jest oczywista.
źródło
Główną różnicą jest to, że kompilator musiał otworzyć plik nagłówka, aby odczytać osłonę dołączania. Dla porównania, pragma raz powoduje, że kompilator śledzi plik i nie wykonuje żadnych operacji we / wy pliku, jeśli natrafi na inny plik dla tego samego pliku. Choć może to zabrzmieć bez znaczenia, może łatwo skalować się przy dużych projektach, szczególnie tych bez dobrego nagłówka, obejmujących dyscypliny.
To powiedziawszy, obecnie kompilatory (w tym GCC) są wystarczająco inteligentne, aby leczyć takich strażników jak pragma. tzn. nie otwierają pliku i unikają kary IO pliku.
W kompilatorach, które nie obsługują pragmy, widziałem ręczne implementacje, które są trochę uciążliwe ..
Osobiście podoba mi się #pragma raz, ponieważ pozwala uniknąć kłopotów z nazewnictwem i potencjalnych błędów literowych. Dla porównania jest to również bardziej elegancki kod. To powiedziawszy, dla przenośnego kodu nie powinno zaszkodzić mieć oba, chyba że kompilator narzeka na to.
źródło
#pragma once
kiedykolwiek!Jeśli używamy msvc lub Qt (do Qt 4.5), ponieważ GCC (do 3.4), msvc oba obsługują
#pragma once
, nie widzę powodu, aby nie używać#pragma once
.Nazwa pliku źródłowego zwykle jest taka sama jak nazwa klasy i wiemy, że czasami potrzebujemy refaktora , aby zmienić nazwę nazwy klasy, wtedy musieliśmy zmienić
#include XXXX
również, więc myślę, że ręczne utrzymanie#include xxxxx
nie jest mądrą pracą. nawet z rozszerzeniem Visual Assist X utrzymanie „xxxx” nie jest konieczną pracą.źródło
Dodatkowa uwaga dla osób myślących, że automatyczne jednorazowe dołączanie plików nagłówkowych jest zawsze pożądane: Generatory kodu buduję przy użyciu podwójnego lub wielokrotnego włączania plików nagłówkowych od dziesięcioleci. Zwłaszcza w przypadku generowania kodów pośredniczących biblioteki protokołów uważam, że bardzo wygodnie jest mieć wyjątkowo przenośny i wydajny generator kodu bez dodatkowych narzędzi i języków. Nie jestem jedynym programistą używającym tego schematu, jak pokazują blogi X-Macros . Nie byłoby to możliwe bez brakującego automatycznego zabezpieczenia.
źródło
X-Macro
funkcji, ale nie jest to główne zastosowanie włączania, czy nie powinno być odwrotnie, jak nagłówek unguard / # pragma multi, gdybyśmy mieli trzymać się DRY?