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 optimization – wzorzec 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
Plik „grandparent.h”
#pragma once
struct foo
{
int member;
};
- Plik „parent.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
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
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ść
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
- ↑ corob-msft, once pragma [online], docs.microsoft.com [dostęp 2021-03-04] (ang.).
- ↑ Guard Macros (The GNU C Preprocessor Internals) [online], gcc.gnu.org [dostęp 2021-03-03] .
- ↑ Even More Experiments with Includes [online], 25 stycznia 2005 [zarchiwizowane z adresu 2008-09-30] .
- ↑ The C Preprocessor: 1. The C Preprocessor [online], gcc.gnu.org [dostęp 2021-03-04] .
- ↑ “Clang” CFE Internals Manual — Clang 12 documentation [online], clang.llvm.org [dostęp 2021-03-04] .
- ↑ clang: File manipulation routines [online], clang.llvm.org [dostęp 2021-03-04] .
- ↑ 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] .
- ↑ clang: Pragma.cpp source file [online] [dostęp 2021-03-04] [zarchiwizowane z adresu 2014-04-04] .
- ↑ embarcadero: #pragma once [online] [dostęp 2021-03-04] .
- ↑ Pragmas - Digital Mars [online] [dostęp 2021-03-04] .}
- ↑ Alternatives to Wrapper #ifndef [online] [dostęp 2021-03-04] .
- ↑ Bug 11569 - there's no substitute for #pragma once [online] [dostęp 2021-03-04] .
- ↑ HP aC++/HPC A.06.29 Programmer's Guide [online] [dostęp 2021-03-04] .
- ↑ IBM Knowledge Center [online], www.ibm.com [dostęp 2021-03-04] (ang.).
- ↑ Intel-supported Pragma Reference [online], Intel [dostęp 2021-03-04] (ang.).
- ↑ t, once pragma [online], docs.microsoft.com [dostęp 2021-03-04] (ang.).
- ↑ IDE help/documentation
- ↑ Documentation – Arm Developer [online], developer.arm.com [dostęp 2021-03-04] .
- ↑ IAR C/C++ Development Guide [online] .
- ↑ Compiler User Guide: Pragmas recognized by the compiler [online], www.keil.com [dostęp 2021-03-04] .
- ↑ Compiler Compatibility - Oracle® Developer Studio 12.5: GCC Compatibility Guide [online], docs.oracle.com [dostęp 2021-03-04] .
- ↑ PGI version 20.4 Documentation for x86 and NVIDIA Processors [online], docs.nvidia.com [dostęp 2021-03-04] .
- ↑ Public Git Hosting - tinycc.git/commitdiff [online], repo.or.cz [dostęp 2021-03-04] .
- ↑ TASKING VX-toolset for TriCore User Guide [online] [dostęp 2021-03-04] .