народ на реддите в +100500 раз устроил флейм по поводу include guards link
вообщем то я не поклонник секты pragma once
но в конце прошлого года на одном из собесов чуть чуть пофлудил
а сейчас решил все таки проверить
итог
пару пет проектов
git ls-files | xargs wc -l
один проект-ик
107820 total
другой проект-ик
87018 total
тестировал под виндой на msvc последним из 19
с изначальным
#ifndef _file_hpp_
#define _file_hpp_
...
#endif
и дополненными
#ifndef _file_hpp_
#define _file_hpp_
#pragma once
...
#endif
результаты не впечатлили
первый
без pragma once — 5.48 минуты
c pragma once — 4.45 минут
второй
без pragma once — 3.41 минут
c pragma once — 3.8 минут
вообщем в пределах погрешности
я бы сказал разницы особой нет
итого
не смотря на то что писанины с pragma once меньше
нарваться на проблемы с одинаковыми файлами по разным путям — больше
останусь на старом добром ifndef
Здравствуйте, reversecode, Вы писали:
R>народ на реддите в +100500 раз устроил флейм по поводу include guards
R>итого R>не смотря на то что писанины с pragma once меньше R>нарваться на проблемы с одинаковыми файлами по разным путям — больше R>останусь на старом добром ifndef
А что не так с прагма уанс, можно вкратце, и почему это секта?
Здравствуйте, reversecode, Вы писали:
R>останусь на старом добром ifndef
Я тоже использую страж включения, но тут нужно сразу решить, или используешь только страж включения, или только pragma once.
А ещё есть другие мысли по этому поводу. Обязательны ли эти конструкции в принципе? Что будет, если их не писать? Очевидно компилятор заругается при повторном включении, но... в случае использования защитных конструкций от повторного включения даём добро на многократные повторные включения.
Вот и ответь мне username, нужны ли стражи включения в своём личном проекте?
Может мы тут все дураки и не лечимся. Пихаем множество включений зная, что они будут проигнорированы благодаря стражу включения. А кто потом будет удалять лишние включения #inlcude? Да, никто и не будет, ведь всё и так работает.
Говорят Объектно-ориентированное программирование — катастрофа на триллион долларов, а что если стражи включения это катастрофа на триллион долларов. Из-за этих уродских макроконструкций код C/C++ становится уродливым, отвлекает программистов на его написание. Бьерн Страуструп вообще-то ратовал за исключение макросов из обихода, но стражи включения как-то пролезли даже в его идеологию.
или или
вы в стандартные хидеры M$ хоть раз смотрели ?
там и pragma once и include guards
собственно мне pragma once был любопытен с точки зрения ускорения компиляции
но после тестовых замеров
и раздумий
мне она ничего не сможет ускорить
поскольку пет проекты все мои
и что куда и зачем я инклудю, я прекрасно контролирую сам
и повторных переинклудов у меня нет
и еще я пришел к выводу что это хороший критерий оценки команды программистов которые работают над одним проектом
если использовался include guard
и в проект добавили еще и pragma once и скорость компиляции возросла
значит программисты которые работают над проектом
слабо представляют дерево зависимости и включают хидеры на глаз не понимая нужно или не нужно
типичный пример недавняя новость про ускорение компиляции линукс ядра после переоптимизации подключения хидеров
меня это посмешило
господа линукс программисты явно не в курсе про pragma once
без переоптимизаций инклудов
банальной pragma once они бы добились тех же самых ускорений при сборке ядра
Здравствуйте, reversecode, Вы писали:
R>или или R>вы в стандартные хидеры M$ хоть раз смотрели ? R>там и pragma once и include guards
А я так и делал вначале, а потом понял, что это крайне глупо. Впрочем я давно уже ушёл от инструментов майков, таких как "вижуал студио". Мне на скорость компиляции класть с высокой колокольни. Эта проблема решается многоядерной компиляцией и покупкой компьютера с более производительным процессором. И то, проект должен быть гигантским, чтобы нужно было такое делать. Но на код я смотрю самолично, а это уже другой разговор.
Да и в целом, я что обезьяна копировать за майками. Например, пихать везде stdafx.h. Нет, если используешь страж включения, то pragma once не нужен. И наоборот, начал пользоваться pragma once, то зачем городить макроконструкции. Оставайся уж тогда на страже включения из трёх макродиректив (#ifndef, #define, #endif).
R>и еще я пришел к выводу что это хороший критерий оценки команды программистов которые работают над одним проектом
Это совершенно другая тема. Мне сейчас не хочется играть в политкорректность, если наниматели используют что-то такое для оценки команды, то они дебилы. Всё же просто, для проекта должны быть правила оформления кода. Сказали писать страж включения, пишешь страж включения. Сказали писать pragma once, пишешь pragma once. Сказали делать и то и другое, делаешь и то и другое. А кто-то может не писать ничего и это будет задокументировано как обязательный стиль для проекта. А если начинаются споры, ну так и пусть катятся эти наниматели колбаской, ищут себе "единомышленников". Если для них главное идеология, а не единый прописанный в правилах проекта стиль кода.
R>меня это посмешило R>господа линукс программисты явно не в курсе про pragma once R>без переоптимизаций инклудов R>банальной pragma once они бы добились тех же самых ускорений при сборке ядра
А кто такие линукс программисты? Те кто делают ядро линукса? Те кто используют системные вызовы линукса? Те кто просто программируют под линуксом? Я как человек постоянно сидящий в Debian, причём по большей части использую его как мультимедийную развлекательную платформу для всего, веб-серфинг, фильмы, игры и так далее, скажу так, мне насрать на оптимизации. А если говорить о сборщиках ядра, ну так это их проект и их дело. В проекте логично следовать принятым соглашениям чтобы код был в едином стиле.
Но вопрос остаётся открытым, а везде ли и всегда нужны конструкции предотвращающие ошибки компилятора при повторном включении?
Представь, что придёт богатый наниматель и скажет, что никаких стражей включения и pragma once быть в его проекте не должно. Что дескать нефиг включать, когда можно не включать. Всё должно быть супер продумано, а не состоять из заплат. Или другое требование, весь проект должен быть в одном файле. А почему бы и нет. Конечно, кто-то скажет, что я сейчас выдумываю, но неудобная правда в том, что стандарта, как обязательно надо, и как обязательно не надо, нет.
R>#ifndef _file_hpp_
R>#define _file_hpp_
R>#pragma once
R>...
R>#endif
R>
R>результаты не впечатлили
Компиляторы, которые оптимизируют #pragma once лучше, чем include guards, делают это тогда, когда #pragma once идёт первой, до неё только, возможно, комментарии и пустые строки.
Но вроде как сейчас компиляторов, оптимизирующих #pragma once лучше — нет. Ранее был таковым MSVC.
М>>А что не так с прагма уанс, можно вкратце, и почему это секта?
R>/somedir1/header_file.h R>/somedir2/header_file.h
R>два хидеры с разным содержанием но одинаковым именем R>включенные в один модуль R>считается что при прагма онце будут проблемы
М>>А что не так с прагма уанс, можно вкратце, и почему это секта?
R>/somedir1/header_file.h R>/somedir2/header_file.h
R>два хидеры с разным содержанием но одинаковым именем R>включенные в один модуль R>считается что при прагма онце будут проблемы
Нет, проблема как раз противоположная. Когда один и тот же файл лежит и включается из разных мест (да такое бывает в реальных проектах) и тогда в случае прагмы эти файлы будут считаться разными и естественно каждый раз включаться заново. А в твоём случае не поможет и ifndef header_file_h. При первом включении header_file.h в таблицу макросов препроцессора будет внесено значение header_file_h и последующие включения header_file.h будут скипнуты. В этом случае как раз и поможет прагма Так что если не знаешь структуры проекта более безопасно писать прагму, но если всё контролируешь, то, конечно, старый добрый ifndef. Единственный минус ifndef — он засирает таблицу макросов ненужной шелухой, но как ты показал сам удар по производительности компиляции незначителен, что в общем не удивительно.
Здравствуйте, YuriV, Вы писали:
YV>Нет, проблема как раз противоположная. Когда один и тот же файл лежит и включается из разных мест (да такое бывает в реальных проектах) и тогда в случае прагмы эти файлы будут считаться разными и естественно каждый раз включаться заново. А в твоём случае не поможет и ifdef имя_файла. При первом включении header_file.h в таблицу макросов препроцессора будет внесено значение header_file_h и следующие включение header_file.h будет скипнуто. В этом случае как раз и поможет прагма Так что если не знаешь структуры проекта более безопасно писать прагму, но если всё контролируешь, то конечно старый добрый ifdef. Единственный минус ifdef он засирает таблицу макросов ненужной шелухой, но как ты показал сам удар по производительности компиляции незначителен, что в общем не удивительно.
Ифдеф еще засирает заголовочные файлы лишними отвлекающими строками. Плюс, если вдруг вручную пишешь этот guard (что редко, но мало ли), можешь ошибиться в написании названия.
Вообще не понимаю, почему не сделали pragma once не на основании полного пути файла, а на основании имени файла и, например, хеша содержимого. Тогда уродливые ifdef ушли бы в прошлое.
Здравствуйте, Андрей Тарасевич, Вы писали:
М>>А что не так с прагма уанс, можно вкратце, и почему это секта?
АТ>Ну хотя бы то, что нет никакого "прагма уанс". Это не стандартная фича.
М М>Ифдеф еще засирает заголовочные файлы лишними отвлекающими строками. Плюс, если вдруг вручную пишешь этот guard (что редко, но мало ли), можешь ошибиться в написании названия. М>Вообще не понимаю, почему не сделали pragma once не на основании полного пути файла, а на основании имени файла и, например, хеша содержимого. Тогда уродливые ifdef ушли бы в прошлое.
Откуда дровишки?
Вики пишет:
...То есть, #pragma once применяется для тех же целей, что и include guard, но требует меньше кода и не допускает возможности коллизии имён.
...
Тем не менее, в релизе 3.4 GCC код обработки команды #pragma once был исправлен для корректной работы с символьными и жёсткими ссылками. Данная возможность была сочтена полезной и предупреждение было убрано.
Здравствуйте, velkin, Вы писали:
R>>останусь на старом добром ifndef
V>Я тоже использую страж включения, но тут нужно сразу решить, или используешь только страж включения, или только pragma once.
Я использую и то и то одновременно. А в чем проблема?
Здравствуйте, удусекшл, Вы писали:
V>>Я тоже использую страж включения, но тут нужно сразу решить, или используешь только страж включения, или только pragma once. У>Я использую и то и то одновременно. А в чем проблема?
В pragma once просто нет смысла, если стоит страж включения ifndef-define-endif. Я себя раньше спрашивал, а зачем я прописываю и то и другое. В итоге забил и оставил лишь страж включения. Но это было очень давно, тогда pragma once ещё не стала практически стандартом.
не однозначно
если судить по msvс шным стандартным хидерам, то да pragma once они делают перед include guard
если вчитываться в реддит или сорсы asio networking, то после
но под утро я решил сделать бранч и потестить и перед
по результатам, все равно разницы нет
если следовать логике, то once должна быть после guard
иначе можно промахнуться в случаях когда одно и тоже имя файла
присутствует в разных директориях ну и once будет как всегда впереди
как я сделал выводы выше топиками
из за того что я сам не плохо контроллирую что и куда я инклудю
и лишних включений у меня нет, то это никак не отразится
а вот на проектах где программисты потеряли уже инклуде флов
и инклудят лишних хидеров
им бы once оптимизации явно помогли
Здравствуйте, reversecode, Вы писали:
R>собственно мне pragma once был любопытен с точки зрения ускорения компиляции
С чего бы ему что-то ускорять?
Вот как надо:
Здравствуйте, andyp, Вы писали:
A>Съехал на прагму давно уже. Основные причины — копипаста гардов с одинаковыми именами и убитые при редактировании эндифы в хвосте файла.
+ переиминование файла не требует дополнительных действий.
R>>собственно мне pragma once был любопытен с точки зрения ускорения компиляции BFE>С чего бы ему что-то ускорять?
Ну, когда компилятор видит подключение файла, он может проверить, не подключался ли он уже. Но, конечно, надо пробежаться по всем инклуд путям, чтобы сформировать полное имя файла. Но это наверное кешируется как-то
Здравствуйте, reversecode, Вы писали:
R>как я сделал выводы выше топиками R>из за того что я сам не плохо контроллирую что и куда я инклудю R>и лишних включений у меня нет, то это никак не отразится
А сколько времени у тебя уходит, чтобы не терять инклюд флоу?
R>а вот на проектах где программисты потеряли уже инклуде флов R>и инклудят лишних хидеров R>им бы once оптимизации явно помогли
Там программисты больше тратят времени на полезные задачи, а прагмуванс сразу вставляют
Здравствуйте, reversecode, Вы писали:
R>господа линукс программисты явно не в курсе про pragma once R>без переоптимизаций инклудов R>банальной pragma once они бы добились тех же самых ускорений при сборке ядра
Там же сделали намного больше, чем переупорядочивание инклудов. Они ещё их переделали, разделили на части и выделили в более атомарные куски. Так что просто pragma once не помог бы.
Кроме того, использование pragma once обсуждалось не раз, но я помню, что была какая-то магия с препросессором, типа некоторые хедеры иногда надо включать по несколько раз, а иногда нет (TRACE_HEADER_MULTI_READ).
Так что только нормальный порядок и мог помочь, что, собственно, и сделали ребята.
Здравствуйте, Михaил, Вы писали:
М>Вообще не понимаю, почему не сделали pragma once не на основании полного пути файла, а на основании имени файла и, например, хеша содержимого. Тогда уродливые ifdef ушли бы в прошлое.
Как раз наоборот, именно на основании пути. Поэтому и получается, что две копии одного и того же файла лежащие в разных местах считаются разными файлами.
Здравствуйте, YuriV, Вы писали:
YV>Когда один и тот же файл лежит и включается из разных мест (да такое бывает в реальных проектах)
Для чего такое может быть нужно, кроме бездумного сваливания файлов в кучу?
YV>тогда в случае прагмы эти файлы будут считаться разными и естественно каждый раз включаться заново.
Зависит от. MSVC, если файлы с одинаковыми именами лежат в разных каталогах, считает их разными только при включении по #include "". При включении по #include <> файл включается только один раз. Это и правильно, учитывая установленный порядок поиска.
Другое дело, что большинство проектов, где одни заголовки включают другие, зачем-то использует форму #include <>, предназначенную для включения любого подходящего файла, вместо формы #include "", которая должна включать "свой" заголовок.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Зависит от. MSVC, если файлы с одинаковыми именами лежат в разных каталогах, считает их разными только при включении по #include "". При включении по #include <> файл включается только один раз. Это и правильно, учитывая установленный порядок поиска.
ЕМ>Другое дело, что большинство проектов, где одни заголовки включают другие, зачем-то использует форму #include <>, предназначенную для включения любого подходящего файла, вместо формы #include "", которая должна включать "свой" заголовок.
Ты ерунду пишешь. Единственное отличие <> от "" — это то, что по "" компилятор сперва пытается найти такой файл относительно текущего обрабатываемого, и если обламывается, то ищет в путях инклуда, как если бы оно включалось через <>. У GCC есть, правда, возможность задавать разные наборы директорий для поиска для этих двух способов подключения, но, по-моему, никто этим особо не пользуется, я и сам как-то случайно об этом вычитал. Не в курсе, есть ли такое в MSVC и других компилерах
Здравствуйте, удусекшл, Вы писали:
У>Единственное отличие <> от "" — это то, что по "" компилятор сперва пытается найти такой файл относительно текущего обрабатываемого
Не только относительно, но и в обратном порядке по истории каталогов, содержащих включаемые файлы. То есть, поиск начинается от каталога текущего файла, и уходит "дальше" от него по истории. Поэтому, если в списке доступных каталогов указано, скажем, два независимых дерева, и какой-то заголовок из первого дерева включил "свой" файл xxx.h, содержащий pragma once, то включение из другого дерева опять же "своего" файла с тем же именем и pragma once будет успешным.
А вот если одно дерево включает "любой" xxx.h, а потом другое также включает "любой", то в обоих случаях по путям будет найден один и тот же, и включен только один раз.
То есть, если проблема коллизии имен и существует, то главным образом по причине некорректного использования форм #include в заголовках.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, удусекшл, Вы писали:
У>>Единственное отличие <> от "" — это то, что по "" компилятор сперва пытается найти такой файл относительно текущего обрабатываемого
ЕМ>Не только относительно, но и в обратном порядке по истории каталогов, содержащих включаемые файлы. То есть, поиск начинается от каталога текущего файла, и уходит "дальше" от него по истории.
By default, the preprocessor looks for header files included by the quote form of the directive #include "file" first relative to the directory of the current file, and then in a preconfigured list of standard system directories. For example, if /usr/include/sys/stat.h contains #include "types.h", GCC looks for types.h first in /usr/include/sys, then in its usual search path.
For the angle-bracket form #include <file>, the preprocessor’s default behavior is to look only in the standard system directories. The exact search directory list depends on the target system, how GCC is configured, and where it is installed. You can find the default search directory list for your version of CPP by invoking it with the -v option. For example,
Хотя, MSVC действительно делает так, как ты написал
Но, видимо, это проблемы особой не создаёт, иначе бы на GCC и MSVC напарывались на разное поведение. Я и там и там компиляю, и проблем никогда не видел
ЕМ>Поэтому, если в списке доступных каталогов указано, скажем, два независимых дерева, и какой-то заголовок из первого дерева включил "свой" файл xxx.h, содержащий pragma once, то включение из другого дерева опять же "своего" файла с тем же именем и pragma once будет успешным.
pragma once работает с абсолютным именем файла, а не тем, которое ты указал в директиве include. Так что не будет никаких проблем. Ну, или микрософт, как обычно, пошел по своему пути и облажался в очередной раз.
ЕМ>А вот если одно дерево включает "любой" xxx.h, а потом другое также включает "любой", то в обоих случаях по путям будет найден один и тот же, и включен только один раз.
ЕМ>То есть, если проблема коллизии имен и существует, то главным образом по причине некорректного использования форм #include в заголовках.
Не уверен, что существует. По крайней мере, если симлинками/хардлинками не баловаться. Не уверен, что MSVC о них знает, для винды штука довольно непривычная. А в GCC проблему вроде решили
М>>А что не так с прагма уанс, можно вкратце, и почему это секта?
R>/somedir1/header_file.h R>/somedir2/header_file.h
R>два хидеры с разным содержанием но одинаковым именем R>включенные в один модуль R>считается что при прагма онце будут проблемы
В худшем случае второй хидер не заинклудится и компилятор ругнется. На проблему не тянет.
Оно удобнее, а теоретические возможные проблемы относятся к категории редко-встречаемых.
То что компилятор не способен понять является ли файл тем-же если включен через другую точку монтирования — личные сексуальные проблемы авторов компилятора, при встрече будут обойдены с минимальными усилиями.
BOM появляется в файлах созданных на винде с добавлением комментариев на местном языке. Это само по себе не хорошо, кривизна GCC тут не причем, много линуксового софта такие файлы вообще не ест, ибо виндовый костыль
Здравствуйте, andyp, Вы писали:
A>копипаста гардов с одинаковыми именами и убитые при редактировании эндифы в хвосте файла.
А вы чем редактируете?
Хороший редактор умеет генерировать гарды по имени создаваемого хедера (плюс рандомные элементы), а хвостовой эндиф визуально связывает с головным ифндефом, так что надо постараться, чтобы что-то сломать.
Здравствуйте, Shtole, Вы писали:
S>А вы чем редактируете?
Разным. От vim до msvc через eclipse и qt creator. Где-то генерация гардов есть, где-то нет, где-то мне тупо лень ее искать.
S>Хороший редактор умеет генерировать гарды по имени создаваемого хедера (плюс рандомные элементы), а хвостовой эндиф визуально связывает с головным ифндефом, так что надо постараться, чтобы что-то сломать.
И тем не менее, регулярно получаю кучу наведенных ошибок из-за нечаянно снесенного endif.
А так, что спорить-то? Я ж всех не принуждаю переходить на прагму. Тем более, что у многих и выбора-то нет — есть корпоративные правила по оформлению кода.
R>итого R>не смотря на то что писанины с pragma once меньше R>нарваться на проблемы с одинаковыми файлами по разным путям — больше R>останусь на старом добром ifndef
извини, но это смешно. как только ты пишешь ifndef-endif — pragma once теряет смысл, т.к. препроцессору все равно нужно теперь парсить файл до конца, чтобы найти подходящий endif.
pragma once нужно использовать без конструкции ifndef-define. естесственно, если компилятор это поддерживает.
Здравствуйте, pokutan, Вы писали:
P>извини, но это смешно. как только ты пишешь ifndef-endif — pragma once теряет смысл, т.к. препроцессору все равно нужно теперь парсить файл до конца, чтобы найти подходящий endif. P>pragma once нужно использовать без конструкции ifndef-define. естесственно, если компилятор это поддерживает.
Что за белиберда? O_o
`#pragma once` обнаруживается препроцессором при первом парсинге файла, то есть тогда, когда его в любом случае придется парсить целиком. И если препроцессор поддерживает `#pragma once`, то он больше этот файл открывать и парсить не будет вообще. То есть все отлично работает именно так, как и хотелось автору кода.
`#pragma once` никак не страдает от наличия ifndef-endif. И где она размещена — внутри ifndef-endif или снаружи — не имеет никакого значения. О каком "все равно нужно теперь парсить файл до конца" вы ведете речь?
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, pokutan, Вы писали:
P>>извини, но это смешно. как только ты пишешь ifndef-endif — pragma once теряет смысл, т.к. препроцессору все равно нужно теперь парсить файл до конца, чтобы найти подходящий endif. P>>pragma once нужно использовать без конструкции ifndef-define. естесственно, если компилятор это поддерживает.
АТ>Что за белиберда? O_o
АТ>`#pragma once` обнаруживается препроцессором при первом парсинге файла, то есть тогда, когда его в любом случае придется парсить целиком. И если препроцессор поддерживает `#pragma once`, то он больше этот файл открывать и парсить не будет вообще. То есть все отлично работает именно так, как и хотелось автору кода.
АТ>`#pragma once` никак не страдает от наличия ifndef-endif. И где она размещена — внутри ifndef-endif или снаружи — не имеет никакого значения. О каком "все равно нужно теперь парсить файл до конца" вы ведете речь?
Из википедии:
In the absence of #include guards around #include directives, the use of #pragma once will improve compilation speed for some compilers 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.
Здравствуйте, pokutan, Вы писали:
P>извини, но это смешно. как только ты пишешь ifndef-endif — pragma once теряет смысл, т.к. препроцессору все равно нужно теперь парсить файл до конца, чтобы найти подходящий endif.
Здравствуйте, pokutan, Вы писали:
P>Из википедии: P>In the absence of #include guards around #include directives, the use of #pragma once will improve compilation speed for some compilers 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.
Тебе помочь понять написанное или попробуешь таки сам напрячься?
Здравствуйте, velkin, Вы писали:
V>В pragma once просто нет смысла, если стоит страж включения ifndef-define-endif. Я себя раньше спрашивал, а зачем я прописываю и то и другое. В итоге забил и оставил лишь страж включения. Но это было очень давно, тогда pragma once ещё не стала практически стандартом.
Теоретически, pragma once должна быть быстрее, так как компилятор даже не будет открывать повторно этот файл, а в случае с гардами таки надо препроцессировать. Поэтому — pragma once. А гарды — на всякий случай, вдруг попадётся компилятор, в котором её нет. Хотя, конечно, это маловероятно, поэтому я стал ленится делать гарды
Здравствуйте, pokutan, Вы писали:
P>>>извини, но это смешно. как только ты пишешь ifndef-endif — pragma once теряет смысл, т.к. препроцессору все равно нужно теперь парсить файл до конца, чтобы найти подходящий endif. P>>>pragma once нужно использовать без конструкции ifndef-define. естесственно, если компилятор это поддерживает.
АТ>>Что за белиберда? O_o
АТ>>`#pragma once` обнаруживается препроцессором при первом парсинге файла, то есть тогда, когда его в любом случае придется парсить целиком. И если препроцессор поддерживает `#pragma once`, то он больше этот файл открывать и парсить не будет вообще. То есть все отлично работает именно так, как и хотелось автору кода.
АТ>>`#pragma once` никак не страдает от наличия ifndef-endif. И где она размещена — внутри ifndef-endif или снаружи — не имеет никакого значения. О каком "все равно нужно теперь парсить файл до конца" вы ведете речь?
P>Из википедии: P>In the absence of #include guards around #include directives, the use of #pragma once will improve compilation speed for some compilers 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.
Так это обычная чушь из википедии. Я уже опроверг ее в своем предыдущем сообщении.
Во-первых, википедия — "мусорный" источник. Поэтому не ясно, к чему вы здесь это цитируете.
Во-вторых, справедливости ради, можно попытаться сыграть "адвоката дьявола" и заметить, что в процитированном пассаже ничего не сказано о том, что будет "in the presence of #include guards", то есть процитированный пассаж совсем не несет того смысла, который вы ему пытаетесь навязать ))) Разумеется, это будет не более чем натягиванием совы на глобус, ибо на само деле в википедии просто написана чушь.
Здравствуйте, удусекшл, Вы писали:
У>Теоретически, pragma once должна быть быстрее, так как компилятор даже не будет открывать повторно этот файл, а в случае с гардами таки надо препроцессировать. Поэтому — pragma once. А гарды — на всякий случай, вдруг попадётся компилятор, в котором её нет. Хотя, конечно, это маловероятно, поэтому я стал ленится делать гарды
`#pragma once` не выжила именно именно потому, что в %99.9 случаев использование include guards является тотальным по отношению к включаемому файлу, то есть полностью функционально эквивалентным `#pragma once`. Такое использование include guards легко распознается препроцессором, который в такой ситуации не будет делать никакого "повторного открытия" и ничего препроцессировать заново не будет.
Другими словами, если препроцессор в состоянии реализовать предполагаемую функциональность `#pragma once`, то он в состоянии реализовать все это и без `#pragma once`- на основе умной обработки include guards. Именно потому от `#pragma once` и отказались.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, удусекшл, Вы писали:
У>>Теоретически, pragma once должна быть быстрее, так как компилятор даже не будет открывать повторно этот файл, а в случае с гардами таки надо препроцессировать. Поэтому — pragma once. А гарды — на всякий случай, вдруг попадётся компилятор, в котором её нет. Хотя, конечно, это маловероятно, поэтому я стал ленится делать гарды
АТ>`#pragma once` не выжила именно именно потому, что в %99.9 случаев использование include guards является тотальным по отношению к включаемому файлу, то есть полностью функционально эквивалентным `#pragma once`. Такое использование include guards легко распознается препроцессором, который в такой ситуации не будет делать никакого "повторного открытия" и ничего препроцессировать заново не будет.
АТ>Другими словами, если препроцессор в состоянии реализовать предполагаемую функциональность `#pragma once`, то он в состоянии реализовать все это и без `#pragma once`- на основе умной обработки include guards. Именно потому от `#pragma once` и отказались.
Вы говорите, что компилятор "хранит" пре-процессед инклуды?
Я не понимаю такой момент: когда компилятор встречает
#include "x.h"
он ДОЛЖЕН открыть этот файл? И, встретив #ifdef — должен найти парный #endif?
И это все — даром (по времени)?
Здравствуйте, Shtole, Вы писали:
S>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>`#pragma once` не выжила <…> от `#pragma once` и отказались.
S>А что значит «не выжила»? И где отказались?
Я говорю про языки С и С++. `#pragma once` когда-то рассматривалась для стандартизации. Одну из основных причин, по которой от нее отказались, я привел выше.
С тех пор уже много времени прошло. Все уже забыли, что когда-то была такая `#pragma once`.
Здравствуйте, VladFein, Вы писали:
У>>>Теоретически, pragma once должна быть быстрее, так как компилятор даже не будет открывать повторно этот файл, а в случае с гардами таки надо препроцессировать. Поэтому — pragma once. А гарды — на всякий случай, вдруг попадётся компилятор, в котором её нет. Хотя, конечно, это маловероятно, поэтому я стал ленится делать гарды
АТ>>`#pragma once` не выжила именно именно потому, что в %99.9 случаев использование include guards является тотальным по отношению к включаемому файлу, то есть полностью функционально эквивалентным `#pragma once`. Такое использование include guards легко распознается препроцессором, который в такой ситуации не будет делать никакого "повторного открытия" и ничего препроцессировать заново не будет.
АТ>>Другими словами, если препроцессор в состоянии реализовать предполагаемую функциональность `#pragma once`, то он в состоянии реализовать все это и без `#pragma once`- на основе умной обработки include guards. Именно потому от `#pragma once` и отказались.
VF>Вы говорите, что компилятор "хранит" пре-процессед инклуды?
Не понял. Я не знаю, что делает ваш компилятор. И зачем "хранить пре-процессед инклуды"? Что такое "хранить пре-процессед инклуды"?
Я лишь говорю, что вся идея, вся суть `#pragma once` заключается именно и только в том, чтобы хранить имена (или внутренние уникальные идентификаторы) уже просмотренных в данной единице трансляции инклудов и не открывать и не парсить их второй раз. Как же еще? Хранить нужно только уникальные идентификаторы файлов (имена, inode иди что-то в этом роде). Никакие "пре-процессед инклуды" хранить не нужно.
Если какой-то компилятор умеет такое делать для `#pragma once`, то он прекрасно сумеет это сделать и для тривиальных применений include guards. То есть никакого преимущества `#pragma once` не предоставляет (кроме того, что в include guards нужно придумывать как-то уникальное макро).
VF>Я не понимаю такой момент: когда компилятор встречает VF>#include "x.h" VF>он ДОЛЖЕН открыть этот файл? И, встретив #ifdef — должен найти парный #endif? VF>И это все — даром (по времени)?
Кому "должен"?
См. выше. Если компилятор уверен, что этот `#include "x.h"` ссылается на уже пропарсенный в этой единице трансляции файл, и в этом файле содержится `#pragma once` или тривиальные include guards, то он может второй раз его не открывать и не парсить. Зачем?
Но это все — вопрос качества реализации, которые пользователя не касаются. Вы просто не будете знать, открывал он его второй раз или нет. Вам это не нужно знать.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Я говорю про языки С и С++. `#pragma once` когда-то рассматривалась для стандартизации. Одну из основных причин, по которой от нее отказались, я привел выше.
А… Стандарт с большой буквы Сэ… Понятно.
АТ>С тех пор уже много времени прошло. Все уже забыли, что когда-то была такая `#pragma once`.
Студия помнит. Авторы библиотек с гитхаба, которые в прошлом году понадобились, тоже.
Здравствуйте, Shtole, Вы писали:
АТ>>С тех пор уже много времени прошло. Все уже забыли, что когда-то была такая `#pragma once`.
S>Студия помнит.
Много кто "помнит". Как я говорил выше, когда-то была реальная попытка стандартизации `#pragma once`, по каковой причине неудивительно, что многие компиляторы бросились ее реализовывать авансом. Но затея с стандартизацией накрылась медным тазом, а реализации в компиляторах так и живут, как рудименты тех времен.
S>Авторы библиотек с гитхаба, которые в прошлом году понадобились, тоже.
За использование голого `#pragma once` — без страховки через include guards — "библиотека с гитхаба" сразу идет ффтопку под взрывы гомерического смеха окружающих. Никому такая библиотека не нужна.
А в остальных случаях `#pragma once` — это карго-культ. Одни "авторы библиотек с гитхаба" подсмотрели (читай: скопипастили) это у других "авторов библиотек с гитхаба". Те в свое время — у третьих и т.д. Они и сами не знают, зачем они это делают. Многие из них, возможно, даже в курсе, что `#pragma once` ничего не дает (по сравнению с include guards), но продолжают механически следовать карго-культу.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Другое дело, что большинство проектов, где одни заголовки включают другие, зачем-то использует форму #include <>, предназначенную для включения любого подходящего файла, вместо формы #include "", которая должна включать "свой" заголовок.
Чего? В С и С++ форма `#include <>` вообще не имеет никакого отношения ни к каким файлам. То, что указывается в треугольных скобках — это не файл вообще. Если используемая вам реализация реализует стандартные заголовки через файлы — флаг ей в руки, но не о каком "предназначенную для включения любого подходящего файла" речи быть не может.
Здравствуйте, reversecode, Вы писали:
R>вообщем то я не поклонник секты pragma once
Сектантство — это как раз делать менее удобный для себя выбор по убеждениям ("все что не в стандарте — в топку"), несмотря на перевес "за-против" в пользу противоположного.
Сам факт того, что эта тема вызывает холивар, является косвенным указанием, что в прагме есть своя ценность. На обсуждение настоящей туфты никто бы своего времени тратить не стал.
R>нарваться на проблемы с одинаковыми файлами по разным путям — больше
Когда одинаковый компонент включается по разным путям, куда выгоднее потратить время не на переписывание инклюдов, а на смену корявых сборочных скриптов на современный менеджер зависимостей.
По ущербности эта логика мне напоминает аргумент, что система сборки должна требовать вручную прописывать каждый файл, и ей нельзя автоматически компилировать все файлы в папке, потому что "а вдруг один из файлов в папке это мусор"? У тех у кого в папках проекта незаметно проскакивает мусор проблемы куда больше и серьезнее, чем выбор системы сборки — им надо над дисциплиной и над тестами работать, а не выбирать тулсы с прицелом на плохую дисциплину.
Люди фокусируются на совершенно пустяковом выборе между A и Б и в упор не видят, что само наличие разницы является симптомом куда большей проблемы на уровне выше. Если компилируемость вашего проекта зависит от выбора между прагмой и гардами, вы либо делаете что-то очень экзотическое (вероятность 0.1%) либо делаете что-то сильно не так (99.9%)
С модулями вообще без инклюдов можно обойтись, но к сожалению в gcc есть баги по модулям.
Жду, когда Circle получит порт под win и туда добавят модули. Или пофиксят gcc.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>В С и С++ форма `#include <>` вообще не имеет никакого отношения ни к каким файлам.
ЕМ>Соответствующий раздел стандарта называется "Source file inclusion".
Мало ли, как он называется. Раздел, описывающий функцию `memcpy` называется "String handling". Это, однако, совсем не означает, что эти функция `memcpy` предназначены для работы со строками.
Уже первые строчки раздела "Source file inclusion" вводят разделение между "header" и "source file": "A #include directive shall identify a header or source file that can be processed by the implementation." "Header" — это не "source file", а существенно более общее и абстрактное понятие.
Директива c <> включает хедеры.
Директива c "" включает файлы и, если файл не найден, ищет хедеры.
R>ну и флейм от инженера интелла R>https://lists.qt-project.org/pipermail/development/2018-October/033733.html
>For example, I have ~/src as a bind-mount to ~/dev/src. That means > ~/src/qt/qt5/qtbase/src/corelib/global/qglobal.h > ~/dev/src/qt/qt5/qtbase/src/corelib/global/qglobal.h >are actually the same file, but they aren't for the effects of #pragma once >because the paths differ.
Ммм, ни капли не выдуманные сетапы в качестве аргументов пошли.
АТ>За использование голого `#pragma once` — без страховки через include guards — "библиотека с гитхаба" сразу идет ффтопку под взрывы гомерического смеха окружающих. Никому такая библиотека не нужна.
`#pragma once` — это сейчас стандарт де-факто, include guards уже на полпути на свалку истории (вычищаются понемногу из легаси, ибо удобнее и есть уникумы которые умудряются разводить срач о code style как их "правильно" именовать :facepalm. Де-факто с++ поддерживает это (вся тройка компиляторов уже хрен знает сколько времени, а кто пользуется допотопными — это их личный выбор и личные проблемы, которые остальных не касаются)
АТ>Многие из них, возможно, даже в курсе, что `#pragma once` ничего не дает (по сравнению с include guards), но продолжают механически следовать карго-культу.
Прагма даёт лаконичность, отсутствие необходимости думать как гварды называть + отсутствие срачей о их "правильном" именовании. Взамен этого гварды как раз ничего не дают — они и есть самый явный карго-культ
Здравствуйте, AeroSun, Вы писали:
AS>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>а существенно более общее и абстрактное понятие.
AS>Это какое?
AS>Хедеры — это как раз самое что ни есть конкретное понятие) Вы наверное с модулями путаете)
Ну это смотря что называть "конкретным".
Хедер — это некая внутренняя компиляторная сущность неизвестной природы, обозначаемая своим идентификатором. Использование идентификатора этой сущности в `#include <...>` приводит к замене данной директивы на содержимое хедера.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Хедер — это некая внутренняя компиляторная сущность неизвестной природы, обозначаемая своим идентификатором. Использование идентификатора этой сущности в `#include <...>` приводит к замене данной директивы на содержимое хедера.
Да нет же.
Всё там известно и ясно любому кто хоть немного программировал на С++.
Вот вам задачка на опровержение: предоставьте рабочий пример с идентификатором этой сущности, а не используя адрес файла
Здравствуйте, AeroSun, Вы писали:
AS>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>Хедер — это некая внутренняя компиляторная сущность неизвестной природы, обозначаемая своим идентификатором. Использование идентификатора этой сущности в `#include <...>` приводит к замене данной директивы на содержимое хедера.
AS>Да нет же.
Я уже закрыл эту тему выше.
AS>Всё там известно и ясно любому
"Всё там известно и ясно любому" [x]
Мои ответы предназначены не для "любых", а для тех, кто хочет разбираться в тонкостях С и С++ ультравысоком уровне.
AS>кто хоть немного программировал на С++.
Это весьма характерный менталитет для "хоть немного программировавших на С++". Прямо по Дэннингу-Крюгеру. Надеюсь, что когда они побольше "попрограммируют на С++", понимания прибавится, убежденности поуменьшится.
Здравствуйте, AeroSun, Вы писали:
AS>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>За использование голого `#pragma once` — без страховки через include guards — "библиотека с гитхаба" сразу идет ффтопку под взрывы гомерического смеха окружающих. Никому такая библиотека не нужна.
AS> AS>`#pragma once` — это сейчас стандарт де-факто, include guards уже на полпути на свалку истории (вычищаются понемногу из легаси, ибо удобнее и есть уникумы которые умудряются разводить срач о code style как их "правильно" именовать :facepalm. AS>Де-факто с++ поддерживает это (вся тройка компиляторов уже хрен знает сколько времени, а кто пользуется допотопными — это их личный выбор и личные проблемы, которые остальных не касаются)
Смех да и только. Никто и нигде не пользуется `#pragma once`, кроме зеленых пионэров, которые изначально скопипастили ее из методичики какого-то своего ПТУ. Но и они быстро избавляются от этой привычки. "Де факто"...
АТ>>Многие из них, возможно, даже в курсе, что `#pragma once` ничего не дает (по сравнению с include guards), но продолжают механически следовать карго-культу.
AS>Прагма даёт лаконичность, отсутствие необходимости думать как гварды называть + отсутствие срачей о их "правильном" именовании. Взамен этого гварды как раз ничего не дают — они и есть самый явный карго-культ
Еще раз: даже те, кто продолжает карго-культово копипастить `#pragma once` из файла в файл, делают это всегда в совокупности с include guards. Голая `#pragma once` — это сразу штамп "пионэрский овнокот" поверх репозитория. Рассказывать же участникам форума про обилие "пионэрскиого овнокота" на гитхабе не обязательно — все об этом и так знают.
Здравствуйте, VladFein, Вы писали:
VF>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>... Голая `#pragma once` — это сразу штамп "пионэрский овнокот" поверх репозитория.
VF>А нету ли у Вас еще таких правил для штампов? Вроде TAB vs spaces? Curly brace placement?
Ой, да их тыщи! (спасибо за ваш хороший вопрос)
Но я не записываю, поэтому приведу лишь те карго-культы, что сразу приходят в голову, ибо встречаются с удивительным постоянством и выраженной сезонностью (читай: каждый год очередному набору "пионэров" раздают все те же методички):
1. Царь всех карго-культов: явное приведение типа на результат `malloc` в С коде
2. Указательная арифметика вместо <stdarg.h> (львовский политех, согласно расследованию ruSO)
3. Золотой фонд индийского программирования: формат `%[]s` в scanf
4. `int i = 0; for (i; i < 10; ++i)`
5. Когда нужно увеличить размер динамического массива, копирование данных из старого массива в новый почему-то делается через третий, специально выделенный временный массив.
6. Чтение файла `while (!f.eof()) { ... }` — "нас так учили"
7. ...
Здравствуйте, Shtole, Вы писали:
S>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>карго-культы
S>Какой смысл вкладывается в словосочетание?
Традиционный. Слепое следование/копирование некоей последовательности действий, без понимания ее семантики. Одним из наиболее распространённых вариантов карго-культа в программировании является выполнение ненужных (читай: ритуальных) действий в совокупности с нужными, сопровождаемое религиозными по своей сути опасениями вида "я не знаю, зачем я это делаю, но я всегда так делал ("нас так учили", "все так делают" и т.п.) и боюсь, что без этого все сломается".
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>>карго-культы
S>>Какой смысл вкладывается в словосочетание?
АТ>Традиционный. Слепое следование/копирование некоей последовательности действий, без понимания ее семантики. Одним из наиболее распространённых вариантов карго-культа в программировании является выполнение ненужных (читай: ритуальных) действий в совокупности с нужными, сопровождаемое религиозными по своей сути опасениями вида "я не знаю, зачем я это делаю, но я всегда так делал ("нас так учили", "все так делают" и т.п.) и боюсь, что без этого все сломается".
Традиционный смысл немного другой: вы построили самолёт из земли, а он не полетел. А вот если он вдруг взял и полетел, то это уже не карго-культ, а рабочая авиационная система, даже если вам не нравится эффективность/эстетика/что-то ещё.
Здравствуйте, Shtole, Вы писали:
S>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>>>карго-культы
S>>>Какой смысл вкладывается в словосочетание?
АТ>>Традиционный. Слепое следование/копирование некоей последовательности действий, без понимания ее семантики. Одним из наиболее распространённых вариантов карго-культа в программировании является выполнение ненужных (читай: ритуальных) действий в совокупности с нужными, сопровождаемое религиозными по своей сути опасениями вида "я не знаю, зачем я это делаю, но я всегда так делал ("нас так учили", "все так делают" и т.п.) и боюсь, что без этого все сломается".
S>Традиционный смысл немного другой: вы построили самолёт из земли, а он не полетел. А вот если он вдруг взял и полетел, то это уже не карго-культ, а рабочая авиационная система, даже если вам не нравится эффективность/эстетика/что-то ещё.
Это какой-то уж очень узкоспециализированный смысл.
Карго-культ — бесполезное и бессмысленное копирование/подражание во всех их проявлениях.
Полетел или не полетел самолет — никакого значения не имеет. А вот обязательное закидывание резиновой галоши в нишу левого шасси (потому что у оригинала в левой нише тоже валялась кем-то забытая галоша) — это уже карго-культ.
это как про того суслика
которого никто не видит
а он есть
pragma once уже поддерживается всеми мажорными компилями
но в стандарте нет
и это один из аргументов противников ее использования
мол зачем юзать то чего нет
сегодня оно есть
а завтра его нет
У>Ну, когда компилятор видит подключение файла, он может проверить, не подключался ли он уже. Но, конечно, надо пробежаться по всем инклуд путям, чтобы сформировать полное имя файла. Но это наверное кешируется как-то
Так делать нельзя, так как define'ы могли поменяться в результате включения этого или других файлов. Можно даже подсчитать (в разумных пределах) число раз включения файла:
#ifdef FILE_INCLUDE_COUNT_5
#error"The include limit for this file has been reached"#endif
#ifdef FILE_INCLUDE_COUNT_4
#define FILE_INCLUDE_COUNT_5 1
#else
#ifdef FILE_INCLUDE_COUNT_3
#define FILE_INCLUDE_COUNT_4 1
#else
#ifdef FILE_INCLUDE_COUNT_2
#define FILE_INCLUDE_COUNT_3 1
#else
#ifdef FILE_INCLUDE_COUNT_1
#define FILE_INCLUDE_COUNT_2 1
#else
#define FILE_INCLUDE_COUNT_1 1
#endif
Понятно, что если подумать, то можно сделать красивше, но — нет, не надо так делать.
Здравствуйте, reversecode, Вы писали:
R>не смотря на то что писанины с pragma once меньше R>нарваться на проблемы с одинаковыми файлами по разным путям — больше R>останусь на старом добром ifndef
Нарваться на одинаковые файлы по разным путям — эээ, а привести свой проект в нормальное состояние никак нельзя?
Если там по-настоящему одинаковые файлы (одни и те же сырцы зачем-то скопированы, или же одну внешнюю библиотеку ссылками раскидали по подпроектам, причём в публичных их частях) — то... один раз причесать, чтобы такого не было.
Выделить эти сырцы в отдельный подпроект, положить в отдельное место, настроить пути к нему.
Если же там одноимённые файлы с разным содержимым (разные версии одной библиотеке раскидали по подпроектам), то добро пожаловать в волшебный мир нарушения ODR.
И он покажет своё волшебство и с прагмой, и с ифдефом, только по-разному.
Я вот что-то не верю, что при выпуске каждой новой версии библиотеки авторы заморачиваются и обновляют все уникальные детальки всех инклуд-гардов.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>`#pragma once` не выжила
"отучаемся говорить за всех"
AT> именно именно потому, что в %99.9 случаев использование include guards является тотальным по отношению к включаемому файлу, то есть полностью функционально эквивалентным `#pragma once`. Такое использование include guards легко распознается препроцессором, который в такой ситуации не будет делать никакого "повторного открытия" и ничего препроцессировать заново не будет.
АТ>Другими словами, если препроцессор в состоянии реализовать предполагаемую функциональность `#pragma once`, то он в состоянии реализовать все это и без `#pragma once`- на основе умной обработки include guards. Именно потому от `#pragma once` и отказались.
В состоянии распознать и распознаёт — это две большие разницы.
Препроцессор, вообще-то, штука очень тупая.
Конечно, можно обмазать его эвристиками, вида "если встретил ifdef-define-.....-endif-EOF" — то считать это прагмой ванс и больше никогда не включать этот файл.
В таком случае, несрабатывание эвристики приведёт к дефолтному поведению.