LINUX.ORG.RU

#pragma once


0

1

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

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

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

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

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

#ifndef UTIL_H
#include "util.h"
#endif

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

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

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

int include_or_not_the_header( const char * path )
{
    if ( pragma_onced_headers_cache_contains( path ) )
        return DONT_INCLUDE_THIS_HEADER;

    if ( does_header_contain_pragma_once( path ) )
        pragma_onced_headers_cache_add( path );
    
    return INCLUDE_THIS_HEADER_PLEASE;
}

Если кто сможет назвать хоть один компилятор (помимо мирно лежащих в гробах) без поддержки #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 нестандартизована, поэтому использовать это можно только на свой страх и риск (в т.ч. риск отвечать пользователям, почему ваша программа не компилируется).

alex_custov ★★★★★ ()
Ответ на: комментарий от alex_custov

> тебе заняться нечем? :)

Как говорит наш тимлид из Бремена: «Yes and no».

Dendy ★★★★★ ()
Ответ на: комментарий от alex_custov

> pragma once нестандартизована, поэтому использовать это можно только на свой страх и риск

Хороший аргумент для человека, далёкого от темы. Приблизительно он звучит как «Windows пользоваться можно только на свой страх и риск, потому что Microsoft завтра обанкротится и Windows канет в лету». Да, у проприетарного ПО есть свои недостатки, но риск банкротства МС - приблизительно из той же области фантастики, как и шанс, что завтра выйдет компилятор без поддержки #pragma once, под который ваша программа должна кровь из носу собираться.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

>>Хороший аргумент для человека, далёкого от темы

Когда-то я писал под АРМ, используемый компилятор не поддерживал pragma once. Если ты ГАРАНТИРУЕШЬ, что любой компилятор под любую архитектуру будет поддерживать pragma once, я буду это использовать с удовольствием. pragma once нестандартизован, тут больше нечего добавить.

alex_custov ★★★★★ ()
Ответ на: комментарий от Dendy

А я вот кодю на шарпе, у меня нет ни того, ни другого. И я очень рад!

hibou ★★★★★ ()

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

Без макросов написать более-менее крупное кроссплатформенное приложение на C и C++ не получится. Такова, увы, суровая реальность.

Именно отсюда и родился #pragma once - тот самый стандарт, призванный решить существовавшие проблемы с включением заголовочников.

А ISO & IEC об этом стандарте в курсе? =)

2. Конфликт имён.

В качестве решения этой очень маловероятной проблемы могу предложить использование UUID'ов.

3. Поощрение к хитростям.

В C/C++ и так существует бесконечное количество способов выстрелить себе в ногу так, что в радиусе ста километров останутся только руины. А тут «поощрение», надо же...

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

Работают и есть не просят. Этого достаточно.

Аргументы за и против

Ты бредишь. Header guards от pragma once ни чем принципиально не отличаются. Работает и то и другое. Просто в использовании и то и другое. Это всё равно что искать плюсы и минусы у красного и синего фломастеров...

mironov_ivan ★★★★★ ()

вот когда оно будет в стандарте, тогда и поговорим. а пока что это — непортабельное расширение. в частности pcc его (пока?) не поддерживает.

proof:

demon:20$ pcc -Wall -o test test.c
test.c, line 9: warning: unknown pragma
demon:21$ cat test.c         
#pragma once
int main() { return 0; }

beastie ★★★★★ ()
Ответ на: комментарий от alex_custov

> Когда-то я писал под АРМ

Год хотя бы скажите, когда это было. Потому как я прямо сейчас собираю под ARM и MIPS с помощью toolchain'ов без всяких проблем.

pragma once нестандартизован, тут больше нечего добавить.


Другими словами, вы признаёте, что #pragma once - это однозначно верное решение, а header guards пора на свалку истории. Но вас смущает отсутствие поддержки ISO, верно?

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

>>Год хотя бы скажите, когда это было. Потому как я прямо сейчас собираю под ARM и MIPS с помощью toolchain'ов без всяких проблем.

три года назад, gcc-3.что-то-там собранный руками (но соответствующий стандарту)

Другими словами, вы признаёте, что #pragma once - это однозначно верное решение, а header guards пора на свалку истории. Но вас смущает отсутствие поддержки ISO, верно?


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

alex_custov ★★★★★ ()
Ответ на: комментарий от mironov_ivan

> Без макросов написать более-менее крупное кроссплатформенное приложение на C и C++ не получится.

Кроссплатформенность можем обсудить в другой теме.

А ISO & IEC об этом стандарте в курсе? =)


В курсе, но если ждать пока гора придёт к Магомеду...

В C/C++ и так существует бесконечное количество способов выстрелить себе в ногу так, что в радиусе ста километров останутся только руины.


Мягко говоря, аргумент вида «и так проблем полно» - неубедителен. Таким образом обсуждая другую особенность C++ можно сказать, мол, C++ и так полон хаков, например - header guards. Замкнутый круг какой-то. Оставим другие темы на потом, сегодня на повестке - сабж.

Header guards от pragma once ни чем принципиально не отличаются.


Это примерно как исходный код принципиально не отличается от обфусцированного - компилятору монописуарно что обрабатывать. Здесь же речь - об отличиях. Отличиях для программиста, а не для машины. Я попробовал их перечислить в теле темы.

Dendy ★★★★★ ()
Ответ на: комментарий от alex_custov

> три года назад

Нашёл официальную документацию ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491a/BCFFDHJH...

можно только на свой страх и риск


Страх и риск чего? Возможностью внезапного бекпортирования под очень древнюю платформу? Закончите предложение, пожалуйста. Риск он ведь в процентах измеряется, а то тут как в анекдоте, шанс встретить на улице динозавра 50/50.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

> Кроссплатформенность можем обсудить в другой теме.

А в этой теме осбуждать только твою абсолютною правоту?

melkor217 ★★★★★ ()
Ответ на: комментарий от beastie

> в частности pcc его (пока?) не поддерживает.

Спасибо, нужно будет проверить. Я так понимаю на рынке компиляторов у pcc маленькая специфичная ниша?

Dendy ★★★★★ ()
Ответ на: комментарий от melkor217

Было бы интересно собрать статистику, кто чем пользуется. И аргументы конечно же. Вариант «пользуюсь тем-то, потому что никогда об этом не задумывался» - тоже подходит.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

>>Нашёл официальную документацию ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491a/BCFFDHJH...

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

Страх и риск чего?


Страх и риск того, что это не заработает. Любой стандарт де-факто имеет эти риски. Не надо потом доказывать, что ты прав, когда тебе покажут документ и попросят показать пункт. Кстати

http://www.youtube.com/watch?v=1cAPFpkUlvs

:))

alex_custov ★★★★★ ()
Ответ на: комментарий от Dendy

тебе IMHO и в самом деле заняться нечем :)

т.е. то, что ты предлогаеш это что-то вроде:

#if _MSC_VER >= 1000 || GCC_VERSION >= 3400
#pragma once
#endif

#ifndef _MY_HEADER_H
#define _MY_HEADER_H

/* some declarations */

#endif

ну и нафига оно?

PS: компилятор, который эту прагму не поддерживает я тебе уже назвал. наверняка есть и другие.

beastie ★★★★★ ()
Ответ на: комментарий от Dendy

>>Было бы интересно собрать статистику, кто чем пользуется. И аргументы конечно же. Вариант «пользуюсь тем-то, потому что никогда об этом не задумывался» - тоже подходит.

Для этого надо делать опрос на главной, это будет получше :)

alex_custov ★★★★★ ()

ТС упорот на ночь глядя. Тема ниочём.

xTumaNx ()
Ответ на: комментарий от alex_custov

> Страх и риск того, что это не заработает.

Понятно, что из-за того, что не заработает. Вопрос, из-за чего оно может не заработать и каков риск в процентах?

покажут документ и попросят показать пункт


Если вы про коммерческое ПО, то там список поддерживаемых компиляторов и прочих утилит сборки часто гвоздями прибит к конкретным версиям. Писать проприетарный код на будущее под неизвестный компилятор - опять же, из области фантастики.

Dendy ★★★★★ ()
Ответ на: комментарий от beastie

> т.е. то, что ты предлогаеш это что-то вроде

Наоборот - оставить код только с #pragma once и ограничиться компиляторами его поддерживающими. Степень адекватности такого выбора будет напрямую зависеть от типа используемого проекта. А абсолютном большинстве проектов, по крайней мере в C++, это допустимо.

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


Наверняка. Вопрос в том - насколько они востребованы и какой процент их использования.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

... каков риск в процентах?

Предлагаю пойти дальше, дополнительно закинуться ВЕЩЕСТВАМИ и попробовать рассчитать стоимость разработки и TCO конечного продукта разработанного с использованием Технологии #Pragma Once Enterprize 2011 (tm) и с использованием Технологии Header Guards 4.2.

mironov_ivan ★★★★★ ()
Ответ на: комментарий от mironov_ivan

Попробую упростить задачу. Назовите хотя бы один C++ компилятор без поддержки #pragma once.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

Назовите хотя бы один C++ компилятор без поддержки #pragma once.

Зачем?

mironov_ivan ★★★★★ ()

Dendy

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

Хм. Небольшое моделирование ситуации показывает, что компилятор с этим вполне справляется. Любопытно, что ранее документация GCC заявляла, дескать, #gragma once давно obsolete. Теперь указывают на плохую портируемость. Прогресс, однако.

Pina ()
Ответ на: комментарий от mironov_ivan

Чтобы выбиться из риска в 0% получить некомпилируемый код. Пусть будет хотя бы 0.001%.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

Чтобы выбиться из риска в 0% получить некомпилируемый код. Пусть будет хотя бы 0.001%.

Зачем? Пусть будет 0%. От этого #infndef/#define/#endif работать не перестанет.

mironov_ivan ★★★★★ ()
Ответ на: комментарий от beastie

> вот когда оно будет в стандарте, тогда и поговорим. а пока что это — непортабельное расширение. в частности pcc его (пока?) не поддерживает.

кстате интересно что (в не PPC) — на это решание GCC намекает как на стандартное :-)

# file: inc.h

#pragma once

#include <string>

std::string inc_func() {
    return std::string("hello word");
}
# file: main.cpp

#include <iostream>

#include "inc.h"
#include "inc.h"

int main() {
    std::string word = inc_func();
    
    std::cout << word << std::endl;
    
    return 0;
}
$ g++ -std=c++98 -pedantic -Wall -o app main.cpp
$ ./app 
hello word

обратите внимание на "-pedantic" .. который обычно не пропускает навороченные инструкции :-)

user_id_68054 ★★★★★ ()

Сейчас стараюсь везде использовать pragma once. И что-то мне подсказывает, что если припрет, то я потрачу 20 минут на написание скрипта, который пробежит по все хидерам и заменит pragma once на ifndef.

Пользую прагму, т.к. 1. Напарывался на конфликт имен 2. Не нужно заморачиваться с «выдумыванием» макросов (я знаю, что IDE их автоматом ставить могут, но про переимещение файлов уже ТС сказал)

kulti ★★ ()

А кто-то использует и то и то.

Booster ★★ ()

Кстати насчёт бородатых программистов, некоторое время назад работал в компании где юзался gcc 2x и gcc 3x, и да там в основном у всех уже растёт борода. ^)

Booster ★★ ()

честно сказать, я над этим даже никогда и не задумывался... всегда IDE вставлял header guards попробую как-нибудь изменить шаблоны на прагму хотя бы из-за того, что для меня это более красивое решение.

frozenix ★★★ ()

> стали ложить
При всем уважении к труду и идеям ТС, «ложить» меня убивает...

svu ★★★★★ ()

Очень интересно. Не задумывался о недостатках header guards (а они в вполне очевидны) и не знал о существовании pragma once. По всему выходит что pragma once лучше, однако от использования воздержусь в виду отсутствия в стандарте. Пошёл переписывать сниппеты для header guards. Нужно добавить туда какую-нибудь уникальную строчку.

KblCb ★★★★★ ()
Ответ на: комментарий от svu

>> стали ложить

При всем уважении к труду и идеям ТС, «ложить» меня убивает...


«Критикуя - предлагай». Как по-вашему будет правильно?

Dendy ★★★★★ ()
Ответ на: комментарий от svu

(пожалуй, вопрос убил еще больше, чем «ложить»)

svu ★★★★★ ()
Ответ на: комментарий от Dendy

> Мягко говоря, аргумент вида «и так проблем полно» - неубедителен. Таким образом обсуждая другую особенность C++ можно сказать, мол, C++ и так полон хаков, например - header guards. Замкнутый круг какой-то.

Эволюционный процесс улучшения с++ будет меееееедленным, и вряд ли ты кого убедишь пользоваться чем-то вне стандарта.

А вот если сделать поверх с++ какой-то язык, по семантике не сильно от него отличающийся, но дающий возможность запрещать простреливание ног (с возможностью разрешать это в отдельных файлах) и писать покороче и пояснее — тогда да.

Там вообще можно было бы обойтись без этой прагмы.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от svu

> класть же!

То-есть по-вашему однозначно правильными будут вторые варианты?

1. Класс А положил в класс Б значение.
2. Класс А поклал в класс Б значение.

1. Значение лежит в классе А.
2. Значение покладено в классе А.

Dendy ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

> А вот если сделать поверх с++ какой-то язык

Миграция с C++ на некий язык С+++ - ещё более сомнительный и долгосрочный ход, чем добавить в компиляторы поддержку общепринятой директивы.

Там вообще можно было бы обойтись без этой прагмы.


И сейчас можно - с помощью #import вместо #include.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

Вы это серьезно спрашиваете???? Правильные варианты 1 и 1, разумеется. Но в случае, использованном вами - только «класть».

Интересно, в каком Вы классе (или что у Вас было по русскому в школе).

svu ★★★★★ ()
Ответ на: комментарий от Dendy

> И сейчас можно - с помощью #import вместо #include.

но в msvc это будет означать совсем-совсем другое

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от svu

> Интересно, в каком Вы классе (или что у Вас было по русскому в школе).

Скорее, стоит спросить «откуда Вы», т.к. в разных местностях бывает свой русский язык :-)

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от svu

серьезно

серьёзно

????

?

вами

Вы

Вы уж определитесь, с большой или с маленькой.

Использование «положить» и «класть» в русском языке неоднозначно, фактически это одно слово с двумя корнями, причём второе больше похоже на паразит. Я понимаю, что вы блюдёте за чистоту языка, но шанс ошибиться при использовании этого слова зашкаливает. Поберегите нервы, ведь если каждый раз

«ложить» меня убивает

так и здоровье подорвать недолго.

И да, заканчиваем оффтоп.

Dendy ★★★★★ ()
Ответ на: комментарий от Dendy

«положить» и «класть»

Вот именно - «положить», но не «ложить». Второго слова в русском языке нет. Вы меня разочаровали, но от pragma once я все равно не откажусь.

kulti ★★ ()
Ответ на: комментарий от Dendy

> Вы уж определитесь, с большой или с маленькой.
На опечатке поймали, зачОт.

Использование «положить» и «класть» в русском языке неоднозначно

В литературном, в указанных случаях - вполне однозначно. Все остальное называется просторечием, переходящим в неграмотность. Шанс ошибиться постепенно исчезает с практикой и слежением за речью.

так и здоровье подорвать недолго.

Да после ЛОРа его и так уже не осталось. То лапу ломит, то хвост отваливается.

svu ★★★★★ ()
Ответ на: комментарий от kulti

Да уж нет, такая неграмотность ставить pragma once под большооой вопрос!%)

svu ★★★★★ ()

>header guards - это хак и как любому хаку в коде ему не место. Более того, это хак в квадрате из-за использования макросов, что сами по себе есть зло.

Это ваши личные предрассудки, не более.

thesame ★★★★ ()

(=

Я не являюсь адептом какой бы то ни было религии (слово).

Я, впрочем, осознанно выступаю за свободу мысли, слова и доступа к информации.

Вы достигли просветления путём познания всей красоты использования «#pragma once». Работники M$ тоже радуются с Вами, ведь это третье чудо, после Win 3.11 и Visual Studio 6.0, которое было ими создано.

Четвёртое чудо, кстати, универсальный разъём для «ложения»? «поклания»? «размещения»?? «установки»! (сколько интересных русских слов, не правда-ли? А ещё есть не совсем русское «позиционирование». Вам никто, кстати, не мешает придумать парочку новых - филологи будут только рады ) пальчиковых батареек. Люди больше не мучаются в попытках выяснения полярности. Жаль, что всё это закрывается никому не нужными и вредными закрытыми патентами (они ведь не дают использовать изобретение повсеместно и во благо, не оглядываясь на крупные корпорации). И я грущу по этому поводу с китайскими создателями универсальных разъёмов для батареек формата B, C и D =(

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

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

Найдите себя в другом поприще! Изучайте, исследуйте, создавайте! Идите с миром =)

m4n71k0r ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.