Софт-Архив

Pragma Once img-1

Pragma Once

Рейтинг: 4.8/5.0 (1826 проголосовавших)

Категория: Windows: Переводчики

Описание

Pragma once - Development

#pragma once

Я являюсь адептом #pragma once. использую эту директиву во всех своих проектах и поощряю других к тому же. Тем не менее время от времени приходится натыкаться на код с использованием header guards. причём код относительно свежий, без налёта 20-го века. Сей факт меня, как представителя homo sapience (с акцентом на sapience) не перестаёт удивлять.

Я честно поднял для себя этот вопрос, попытался проанализировать, что же движет программистами обоих кланов. Список достоинств и недостатков обоих методов получился примерно следующим:

1. header guards - это хак и как любому хаку в коде ему не место. Более того, это хак в квадрате из-за использования макросов, что сами по себе есть зло. Логика подсказывает, что если же хак превращается в правило - проблему нужно решать на глобальном уровне, причём стандарт должен минимизировать побочные эффекты к нулю. Именно отсюда и родился #pragma once - тот самый стандарт, призванный решить существовавшие проблемы с включением заголовочников.

2. Конфликт имён. Если вы в своём коде добавили util.h с #define UTIL_H внутри, рано или поздно вы наткнётесь на конфликт с 3rdparty-библиотекой с таким же макросом. Единые правила для выбора имён макросов дискредитируют саму их идею - если все будут их придерживаться, то в результате они породят те же конфликты. Остаётся надеяться на генераторы мусорных суффиксов, которые а) идут вразрез с идеей того, что код должен писаться для человека и б) привет, рефакторинг! то-есть, пока. переименовав один заголовочник в другой или просто скопировав код получаем чёрти что.

3. Поощрение к хитростям. Если макрос объявлен, значит его можно и удалить, чтобы потом попробовать включить заголовочник снова. Или смешная до коликов в животе попытка «ускорить» компиляцию следующим хаком:

Которая не только ни на грамм не быстрее, но ещё и вынуждает следить по всему коду, чтобы макрос совпадал.

Конечно подкованный кодер к подобным хитростям чужд, максимум кого ими можно обхитрить - самого себя. Тем не менее неоднозначная семантика header guards вынуждает молодого программиста задуматься - а вдруг таки можно? Однозначная семантика #pragma once решает эту проблему на корню, минимизируя возможные хаки и ошибки к нулю.

4. Распространённость и поддержка компиляторами. Как известно, чем проще код - тем легче его сопровождать. Аргумент сложности реализации #pragma once для меня вообще смешон, поддержка реализуется примерно следующим алгоритмом:

Если кто сможет назвать хоть один компилятор (помимо мирно лежащих в гробах) без поддержки #pragma once - будьте добры. Мой гугл находит только кивания, что суслик как бы есть, но в глаза его никто не видел.

5. Миф о проблемах с символическими ссылками в #pragma once. Давно развеян с тех пор, как в GCC в кеш (см. пример выше) стали ложить не символические ссылки на файлы, а сами файлы.

6. Достоинства header guards. Здесь прочерк.

Итого я пришёл к выводу, что header guards продолжают пользоваться:

1) Осознанно. Бородатые программисты с бородатыми компиляторами со специфичным кодом под специфичные устройства.

2) Неосознанно - все остальные.

Отчасти на пункт 2 повлияли два фактора - ISO и GCC. Первый, насколько я понимаю, до сих пор жмётся, чтобы добавить директиву в стандарт. Второй долгое время выдавал warning на эту директиву, мол deprecated и вообще ай-яй-яй. Пользователи при этом балансировали на грани, а многие поддались общей панике и устроили крестовые походы набеги на #pragma once. насаждая всюду религию header guards. И видимо по инерции не заметили, как ещё в 2004-м году (!!) в GCC 3.4 официально убрали любые комплексы по этому поводу, оставив #pragma once навсегда в списке поддерживаемых директив.

Аргументы за и против, а также список компиляторов без поддержки #pragma once - приветствуются. Примеры сотен кода, в которых используются header guards без аргументации почему - можете оставить себе.

Другие статьи, обзоры программ, новости

Pragma once - это

Pragma once это:

Правильный заголовок этой статьи — #pragma once. Он показан некорректно из-за технических ограничений.

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

File «child.c»

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

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

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

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

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

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

Pragma once

Pragma once

Правильный заголовок этой статьи — #pragma once. Он показан некорректно из-за технических ограничений.

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

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

File «father.h»

File «child.c»

Достоинства и недостатки Править

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

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

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

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

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

PRAGMA - что это?

Тема: #PRAGMA - что это?

03.04.2014, 16:07

куча разных применений.

ИМХО, ей лучше вообще не пользоваться.

ИМХО, это не стандартная директива (в стандарте ее нет), поэтому используют ее разные компиляторы по-разному.

После слова прагма идет значение.

Например, прагмой можно изменить точку входа:

#pragma comment(linker,"/ENTERY:WinMain")

по умолчанию точка входа - это функция main(), но можно замутить другую, иногда в этом есть смысл.

В прагма коммент вообще очень много всего, там можно покопаться с екциями данных и кода, установить выравнивания (вроде как размер исполняемого файла при компиляции кратен какому-то числу, вот это число можно подредактировать), да много всего. Но я не уверен, я не особо этим баловался.

pragma pack - вот этой штукой я пользовался, и даже студентов ей пытал. Есть такая штука в С++, как выравнивание полей в структурах.

грубо говоря

sizeof(T); // какое значение вернет sizeof? -

студенты могут считать что 1, ну и по хреновым методичкам оно там и есть, но а реально все зависит от того, как выравнивает поля компилятор, а управлять этим можно с pragma pack

Еще часто пользуют pragma once чтобы модуль включался при линковке только один раз. Но вместо pragma once всегда можно использовать #ifndef и #define. Вобщем в основном так и делают.

Без лишней необходимости ими лучше не пользоваться, потому что даже прагма пак, которая известна и реально нужна работает не во всех компиляторах.

Вот такая штука эта прагма, я то стараюсь писать портируемый код, поэтому ими не балуюсь. Ну мало ли, напишу я софтину и захочу ее на ведре запустить, но где гарантии, что компилятор С++ на ведре сработает также как компилятор мелкософта или гцц? - никто таких гарантий не дает (и никто не обязан это обеспечивать).

В стандарте я ее чесно не искал, поэтому ИМХО всюду написал.

Pragma once

Директива #pragma определяется стандартом ANSI С для реализации директив, предоставляю­щих компилятору различные инструкции. Стандартный вид #pragma следующий:

Директива argused должна стоять перед функцией. Она используется для устранения предупреж­дений, если аргумент функции, перед которой стоит #pragma, не используется в теле функции.

Чтобы разрешить использовать анонимные структуры, укажите директиву anon_struct. С помо­щью директивы codeseg можно указать сегмент, класс или группу, используемую функцией.

Используя директиву comment, в выходной файл, например, в файл с расширением obj или ехе можно поместить комментарии.

Директива exit определяет одну или несколько функций, вызываемых при завершении програм­мы. Директива startup определяет одну или несколько функций, вызываемых при запуске про­граммы. Они имеют следующий вид:

#pragma exit имя_функции приоритет

#pragma startup имя_функции приоритет

Приоритет — это значение от 64 до 255 (значения от 0 до 63 зарезервированы). Приоритет определяет порядок вызова функций. Если приоритет не указан, то по умолчанию предполагает­ся значение 100. Все функции, выполняющиеся в начале или конце программы, должны объяв­ляться следующим образом:

void f(void);

Следующий пример определяет функцию start(), выполняющуюся в начале программы.

#include <stdio.h>

void start(void);

#pragma startup start 65

Pragma once

pragma once From Seo Wiki - Search Engine Optimization and Programming Languages

In the C and C++ programming languages, #pragma once is a non-standard but widely supported preprocessor directive designed to cause the current source file to be included only once in a single compilation. Thus, #pragma once serves the same purpose as #include guards. but with several advantages, including: less code, avoiding name clashes, and improved compile speed.

File "child.c"

Advantages and disadvantages

Using #pragma once instead of include guards will typically increase compilation speed since it is a higher-level mechanism; the compiler itself can compare filenames or inodes without having to invoke the C preprocessor to scan the header for #ifndef and #endif.

Some compilers such as GCC include special speedup code to recognize and optimize the handling of include guards, and thus little or no speedup benefit is obtained from the use of #pragma once. [1]

Again because the compiler itself is responsible for handling #pragma once. it is not necessary for the programmer to create new macro names such as GRANDFATHER_H in the Include guard article's example. This eliminates the risk of name clashes, meaning that no header file can fail to be included at least once. It also requires less typing than the include guard method.

However, this high-level handling cuts both ways; the programmer must rely on the compiler to handle #pragma once correctly. If the compiler makes a mistake, for example by failing to recognize that two symbolic links with different names point to the same file, then the compilation will fail. Compilers with #pragma once -related bugs included LCC-Win32 as of 2004 [update] [2] [3] and GCC as of 1998 [update]. [4] GCC originally gave a warning declaring #pragma once "obsolete" when compiling code that used it. However, with the 3.4 release of GCC, the #pragma once handling code was fixed to behave correctly with symbolic and hard links. The feature was "un-deprecated" and the warning removed. [5] [6]

You can use both #pragma once and include guards to write portable code that can also take advantage of #pragma once optimizations the compiler may support:

Teknicool - #Pragma Once is Better Than Include Guards

#Pragma Once is Better Than Include Guards

Include guards always seemed like an inconvenient way of making sure header files are only included once to me. Surely it would be better to have a special preprocessor directive to indicate the less common case where you really do want to allow your header to be included multiple times?

Whatever the case, #pragma once has existed for a very long time as an alternative to include guards. Why would you want to use it?

  • You can copy and paste it. It’s inevitable that somebody will copy and paste one header to start writing another and forget to update the include guard symbol.
  • Filename-based conventions for include guard symbols can experience conflicts. Additionally, if you want to refactor code and move the location of some files around, you must remember to update the include guards (and inevitably someone will forget).
  • Pragma once is fast to type and only one line. You could potentially write a macro or script for your editor to automate insertion of include guards (e.g. create a correct symbol based on the filename or generate a UUID), but it’s probably wasted time.

For whatever reason, use of #pragma once is not especially widespread. There’s usually no compelling reason not to use it though. Arguments against its use are usually:

  • Pragma once isn’t portable: This is virtually never a practical consideration. It’s supported properly on all common C/C++ compilers. This includes GCC (properly since 2004 with GCC 3.4 ), Comeau, Clang, Intel, and Microsoft. By properly, I mean a file is included only once even if it’s included again through a symbolic or hard link. I would assume virtually any other C/C++ compiler would support this pragma too, or they could be incompatible with code that works on the compilers that get used for virtually everything in the real world.
  • Pragma once can’t work properly: GCC’s documentation says that the only reason not to use it is because it’s not standard, so that should be one indication that this argument is false. It works properly unless you go out of your way to break it or have a buggy preprocessor.

There are two example situations where you could end up breaking pragma once that I can think of, and neither would form the basis of a particularly compelling argument against using it:

  1. The first example is a code base that contains multiple copies of some headers, where it’s possible for compilation of a source file to involve including more than one of the copies. #pragma once will fail because the copies are separate files, where include guards would work because all the copies would check for the same symbol.
  2. The second example is a code base where it’s possible for compilation of a source file to involve including the same header multiple times via different links. Use of #pragma once will cause issues if this code is accessed through or copied onto a file system that doesn’t support such links (e.g. some network shares, old filesystems) or through a file archive format that doesn’t support storing it. This is because the different links will now appear to the preprocessor as multiple independent files.

The first example is not an argument against pragma once at all. Having multiple copies of the same header is poor from a maintenance point of view and will be less efficient to build than if the header exists in only one location. If multiple copies need to be made for some reason (e.g. some sort of build system?) they should be made as links.

Особенности реализации #pragma once в gcc - Журнал Пушыстого

Журнал Пушыстого

скомпилируем main.c и запустим

> cc main.c && ./a.out

Вопрос, чему будет равно x?

Ок, а теперь внимательно следим за руками:

> touch -r a.h b.h # выравниваем mtime у a.h и b.h

> touch a.h

> cc main.c -MM

main.o: main.c a.h b.h

Обычные зависимости, ничего магического. А теперь снова проделаем наш фокус:

> touch -r a.h b.h

> cc main.c -MM

main.o: main.c a.h

Круто! b.h нам больше не нужен!

Если пораскинуть мозгами, то можно догадаться, что содержимое хедеров у нас одинаковое, mtime у них одинаковый, то есть, думает gcc, это один и тот же файл! Ну а раз такое дело, да ещё и #pragma once, то второй раз тот же хедер инклюдить не нужно.

Действительно, если заглянуть в код gcc (libcpp/files.c:815), то можно увидеть, что, в случае #pragma once (once_only), если mtime и size инклюда совпадает с ранее включённым файлом, то после сравнения содержимого, если файлы идентичны, то функция возвращает false и файл не инклюдится.

/* We may have read the file under a different name. Look

for likely candidates and compare file contents to be sure. */

for (f = pfile->all_files; f; f = f->next_file)

if (f == file)

if ((import || f->once_only)

&& f->err_no == 0

// дальше здесь файл f зачитывается ещё раз в память и сверяется с текущим

// и если у них одинаковое содержимое, то функция возвращает false и не инклюдит файл

same_file_p = read_file (pfile, ref_file)

/* Size might have changed in read_file(). */

&& ref_file->st.st_size == file->st.st_size

&& !memcmp (ref_file->buffer,

file->buffer,

file->st.st_size);

Я то всегда думал, что #pragma once срабатывает при инклюде того же файла в смысле "по тому же пути", ан нет.

В ченджлоге от версии 3.4 можно увидеть небольшую заметку про #pragma once