pragma once

В языках программирования Си и C++ #pragma once — нестандартная, но широко распространённая препроцессорная директива, разработанная для контроля за тем, чтобы конкретный исходный файл при компиляции подключался строго один раз. То есть, #pragma once применяется для тех же целей, что и include guard, но требует меньше кода и не допускает возможности коллизии имён. В наборе компиляторов GCC до версии 3.4 считалась устаревшей и для применения не рекомендовалась.[1] Однако, из-за широкого применения это решение было изменено.[2]

В статье об include guard приводится пример ситуации, в которой нужно использовать тот или иной метод. Выходом является использование #include guard, приведённое там же; вариантом использования #pragma once может быть:

File «grandfather.h»
#pragma once

struct foo {
    int member;
};
File «father.h»
#include "grandfather.h"
File «child.c»
#include "grandfather.h"
#include "father.h"

Поддержка компиляторов

править
Компилятор #pragma once
Clang Да[3]
Comeau C/C++ Да [4]
C++Builder XE3 Да[5]
Digital Mars C++ Да[6]
GCC Да[7] (с версии 3.4[8])
HP C/aC++ Да[9] (по крайней мере с версии A.06.12)
IBM XL C/C++ Да[10] (с версии 13.1.1)
Intel C++ Compiler Да[11]
Microsoft Visual C++ Да[12] (с версии 4.2)
Pelles C Да[13]
ARM DS-5 Да[14]
IAR C/C++ Да[15]
Solaris Studio C/C++ Нет [16][17]

Достоинства и недостатки

править

Применение #pragma once вместо include guard увеличит скорость компиляции во многих случаях благодаря высокоуровневому механизму; компилятор может самостоятельно сравнивать имена файлов или inode'ы без необходимости вызова препроцессора Си для проверки заголовка на наличие #ifndef и #endif.

С другой стороны, некоторые компиляторы, как например, GCC, также используют специальный код для распознавания и оптимизации обработки include guard.[1]

Из-за того, что компилятор сам по себе отвечает за обработку #pragma once, программисту нет необходимости создавать новые имена, например, GRANDFATHER_H. Это исключает риск коллизии имён, то есть заголовочный файл не сможет вызвать ошибку при его подключении. Также приходится набирать меньше текста, нежели при использовании include guard.

Тем не менее, такая высокоуровневая обработка ускоряется в обоих случаях, но программисту приходится полагаться на корректную обработку компилятором #pragma once. Если компилятор совершает ошибку, например, не может распознать ситуацию, когда две символьные ссылки с различными именами указывают на один и тот же файл, то компиляция завершается с ошибкой. Компиляторами, содержащими ошибки, связанные с #pragma once, являются LCC-Win32 версии 2004 года[18][19] и GCC версии 1998 года.[1] GCC первоначально выдавал предупреждение об отключении #pragma once, если компилируемый код использовал её. Тем не менее, в релизе 3.4 GCC код обработки команды #pragma once был исправлен для корректной работы с символьными и жёсткими ссылками. Данная возможность была сочтена полезной и предупреждение было убрано.[20][21]

Можно использовать обе команды, #pragma once и include guards, для написания переносимого кода, что также может принести выгоду от применения #pragma once при оптимизации (если компилятор её поддерживает):

File «grandfather.h»
#pragma once
#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct foo
{
    int member;
};

#endif /* GRANDFATHER_H */

Примечания

править
  1. 1 2 3 The C Preprocessor. Once-Only Include Files. Дата обращения: 6 июня 2008. Архивировано 7 августа 2013 года.
  2. Bug 11569 – there's no substitute for #pragma once. Дата обращения: 21 декабря 2013. Архивировано 24 декабря 2013 года.
  3. clang: clang: Pragma.cpp Source File. Clang.llvm.org. Дата обращения: 19 августа 2013. Архивировано из оригинала 4 апреля 2014 года.
  4. Comeau C++ Pre-Release User Documentation: Pragmas. Comeaucomputing.com. Дата обращения: 19 августа 2013. Архивировано из оригинала 11 декабря 2013 года.
  5. #pragma once - RAD Studio XE3. Docwiki.embarcadero.com (2 декабря 2010). Дата обращения: 19 августа 2013. Архивировано 12 декабря 2013 года.
  6. Pragmas. Digital Mars. Дата обращения: 19 августа 2013. Архивировано 12 декабря 2013 года.
  7. Alternatives to Wrapper #ifndef. Gcc.gnu.org. Дата обращения: 20 августа 2013. Архивировано 4 марта 2016 года.
  8. GCC 3.4 Release Series — Changes, New Features, and Fixes. Gcc.gnu.org. Дата обращения: 19 августа 2013. Архивировано 10 июля 2010 года.
  9. HP aC++/HP ANSI C A.06.26 Release Notes HP Integrity servers (англ.). HP Support Center. Дата обращения: 5 июня 2016. Архивировано 23 июня 2016 года.
  10. Supported GCC pragmas. IBM. Дата обращения: 20 февраля 2015. Архивировано 4 марта 2016 года.
  11. Diagnostic 1782: #pragma once is obsolete. Use #ifndef guard instead. Intel Developer Zones. Дата обращения: 4 декабря 2013. Архивировано 11 декабря 2013 года.
  12. once (C/C++). Msdn.microsoft.com. Дата обращения: 19 августа 2013. Архивировано 10 августа 2016 года.
  13. IDE help/documentation
  14. ARM Information Center. ARM. Дата обращения: 17 декабря 2013. Архивировано 7 октября 2016 года.
  15. IAR C/C++ Development Guide. IAR Systems. Дата обращения: 4 декабря 2013. Архивировано из оригинала 16 мая 2017 года.
  16. Solaris Studio 12.4: C++ User's Guide. Oracle. Дата обращения: 20 февраля 2015. Архивировано 9 октября 2016 года.
  17. Solaris Studio 12.4: C User's Guide. Oracle. Дата обращения: 20 февраля 2015. Архивировано 4 марта 2016 года.
  18. Сообщение из обсуждения standard change. Lcc-win32 accepts and implements #pragma once
  19. Сообщение из обсуждения thoughts on an old proposal: #once
  20. Obsolete once-only headers. Дата обращения: 6 июня 2008. Архивировано 2 января 2007 года.
  21. GCC 3.4 Release Series. Changes, New Features, and Fixes. Дата обращения: 6 июня 2008. Архивировано 10 июля 2010 года.

Дополнительные источники

править