pragma once

Z Wikipedii, wolnej encyklopedii

pragma once – niestandardowa, ale szeroko obsługiwana dyrektywa kompilatora w językach programowania C i C ++. Jest zaprojektowana w celu zapobiegania zawarcia kodu źródłowego wiele razy w jednej kompilacji[1]. Dyrektywa #pragma once funkcjonuje podobnie jak tzw. multiple include optimizationwzorzec projektowy wykorzystujący standardowe dyrektywy preprocesora[2], ale z dodatkowymi zaletami, w tym: mniej kodu, unikanie kolizji nazw, a czasem nawet poprawę szybkości kompilacji[3]. Z drugiej strony, #pragma once niekoniecznie jest dostępna we wszystkich kompilatorach, a jej implementacja jest zawiła i może być zawodna.

Przykład[edytuj | edytuj kod]

Plik „grandparent.h”

#pragma once

struct foo 
{
  int member;
};
Plik „parent.h”
#include "grandparent.h"
Plik „child.c”
#include "grandparent.h"
#include "parent.h"

W tym przykładzie zawarcie grandparent.h zarówno w parent.h jak i child.c zwykle spowodowałoby błąd kompilacji, ponieważ struktura o nazwie foo może być zdefiniowana tylko raz w danej kompilacji. Dyrektywa #pragma once istnieje po to żeby uniknąć wielokrotnego zawarcia pliku grandparent.h.

Zalety[edytuj | edytuj kod]

Użycie#pragma once umożliwia preprocesorowi C dołączenie pliku, gdy jest potrzebny, w przeciwnym razie zignorowanie dyrektywy #include. Ma to wpływ na preprocesor C i pozwala programistom na wyrażanie zależności plików w łatwy sposób, eliminując potrzebę ręcznego zarządzania.


Najczęstszą alternatywą dla #pragma once jest użycie #define do ustawienia makra chroniącego #include, którego nazwa jest wybierana przez programistę i jest unikalna dla danego pliku. Na przykład:

#ifndef GRANDPARENT_H
#define GRANDPARENT_H
... contents of grandparent.h
#endif /* !GRANDPARENT_H */

Takie podejście w minimalnym stopniu gwarantuje, że zawarty plik nie będzie uwzględniony więcej niż raz. Jest to bardziej szczegółowe, wymaga więcej pracy, oraz jest podatne na błędy programisty, ponieważ nie ma dostępnych dla kompilatora mechanizmów zapobiegających przypadkowemu użyciu tej samej nazwy makra w więcej niż jednym pliku, co spowodowałoby, że tylko jeden z plików byłby zawarty przez preprocesor. Takie błędy, pomimo że bardzo prawdopodobne jest ich wykrycie, ale mogą skomplikować raport o błędach kompilatora. Ponieważ sam preprocesor jest odpowiedzialny za #pragma once, programista nie może spowodować kolizji nazw.

W przypadku braku makra zabezpieczającego wokół dyrektyw #include, przy użyciu #pragma once prawdopodobna jest poprawa szybkości kompilacji niektórych kompilatorów, ponieważ jest to wbudowany mechanizm; sam kompilator może porównywać nazwy plików bez konieczności wywoływania preprocesora celu przeszukania nagłówka w poszukiwaniu dyrektyw #ifndef i #endif. Ponieważ jednak makra osłaniające #include pojawiają się bardzo często, a obciążenie związane z otwieraniem plików jest znaczące, kompilatory często optymalizują takie makra, co może spowodować, że będą one tak szybkie, jak #pragma once[4][5][6].

Uwagi[edytuj | edytuj kod]

Identyfikacja tego samego pliku w systemie plików nie jest łatwym zadaniem[7]. Dowiązania symboliczne, a zwłaszcza dowiązania twarde, mogą powodować, że ten sam plik będzie znajdował się pod różnymi nazwami w różnych folderach. Kompilatory mogą używać metody, która porównuje rozmiar pliku, czas modyfikacji i zawartość. Dodatkowo #pragma once może spowodować problemy, jeśli ten sam plik jest celowo kopiowany do kilku części projektu, np. Podczas przygotowywania kompilacji. W przypadku gdy makra zabezpieczające zawarcie nadal chroniłyby przed wielokrotnymi definicjami, #pragma once może różnie potraktować pliki. Trudności te, wraz z problemami związanymi z określeniem, co stanowi ten sam plik w obecności twardych linków, sieciowych systemów plików itp., dotąd uniemożliwiły standardyzację#pragma once

Zastosowanie makra chroniącego umożliwia zależnemu na rozpoznawanie i zareagowanie na różnice w semantyce lub interfejsach konkurencyjnych alternatyw. Na przykład,

#include TLS_API_MACRO /* defined on the command line */

...

#if defined TLS_A_H
... use one known API
#elif defined TLS_B_H
... use another known API
#else
#error "unrecognized TLS API"
#endif

W tym przypadku bezpośrednie określenie, który interfejs API jest dostępny, jest umożliwione przez to, że zawarty plik zadeklarował się za pomocą swojego makra chroniącego.

Dostępność[edytuj | edytuj kod]

Kompilator #pragma once
Clang Obsługiwana[8]
Comeau C / C ++ Obsługiwana
Cray C i C ++ Obsługiwana (od wersji 9.0)
C ++ Builder XE3 Obsługiwana[9]
Digital Mars C ++ Obsługiwana[10]
GCC Obsługiwana[11] (oficjalnie od wersji 3.4[7][12])
HP C / aC ++ Obsługiwana[13] (od wersji A.06.12)
IBM XL C / C ++ Obsługiwana[14] (od wersji 13.1.1)
Intel C ++ Compiler Nieobsługiwana[15]
Microsoft Visual C ++ Obsługiwana[16] (od wersji 4.2)
NVIDIA CUDA Kompilator Obsługiwana (w zależności od bazowego kompilatora hosta)
Pelles C Obsługiwana[17]
ARM DS-5 Obsługiwana[18]
IAR C / C ++ Nieokreślone zachowanie[19]
Keil CC 5 Obsługiwana[20]
Oracle Developer Studio C / C ++ Obsługiwana[21](od wersji 12,5)
Portland Group C / C ++ Obsługiwana[22] (od wersji 17,4)
TinyCC Obsługiwana[23] (od kwietnia 2015 r.)
TASKING VX-toolset for TriCore: C compiler Obsługiwana[24] (od wersji 6.2r2)

Przypisy[edytuj | edytuj kod]

  1. corob-msft, once pragma [online], docs.microsoft.com [dostęp 2021-03-04] (ang.).
  2. Guard Macros (The GNU C Preprocessor Internals) [online], gcc.gnu.org [dostęp 2021-03-03].
  3. Even More Experiments with Includes [online], 25 stycznia 2005 [zarchiwizowane z adresu 2008-09-30].
  4. The C Preprocessor: 1. The C Preprocessor [online], gcc.gnu.org [dostęp 2021-03-04].
  5. “Clang” CFE Internals Manual — Clang 12 documentation [online], clang.llvm.org [dostęp 2021-03-04].
  6. clang: File manipulation routines [online], clang.llvm.org [dostęp 2021-03-04].
  7. a b GCC 3.4 Release Series — Changes, New Features, and Fixes - GNU Project - Free Software Foundation (FSF) [online], gcc.gnu.org [dostęp 2021-03-04].
  8. clang: Pragma.cpp source file [online] [dostęp 2021-03-04] [zarchiwizowane z adresu 2014-04-04].
  9. embarcadero: #pragma once [online] [dostęp 2021-03-04].
  10. Pragmas - Digital Mars [online] [dostęp 2021-03-04].}
  11. Alternatives to Wrapper #ifndef [online] [dostęp 2021-03-04].
  12. Bug 11569 - there's no substitute for #pragma once [online] [dostęp 2021-03-04].
  13. HP aC++/HPC A.06.29 Programmer's Guide [online] [dostęp 2021-03-04].
  14. IBM Knowledge Center [online], www.ibm.com [dostęp 2021-03-04] (ang.).
  15. Intel-supported Pragma Reference [online], Intel [dostęp 2021-03-04] (ang.).
  16. t, once pragma [online], docs.microsoft.com [dostęp 2021-03-04] (ang.).
  17. IDE help/documentation
  18. Documentation – Arm Developer [online], developer.arm.com [dostęp 2021-03-04].
  19. IAR C/C++ Development Guide [online].
  20. Compiler User Guide: Pragmas recognized by the compiler [online], www.keil.com [dostęp 2021-03-04].
  21. Compiler Compatibility - Oracle® Developer Studio 12.5: GCC Compatibility Guide [online], docs.oracle.com [dostęp 2021-03-04].
  22. PGI version 20.4 Documentation for x86 and NVIDIA Processors [online], docs.nvidia.com [dostęp 2021-03-04].
  23. Public Git Hosting - tinycc.git/commitdiff [online], repo.or.cz [dostęp 2021-03-04].
  24. TASKING VX-toolset for TriCore User Guide [online] [dostęp 2021-03-04].