#pragma twice
От: Кодт Россия  
Дата: 22.07.14 23:41
Оценка: 37 (10) :))
http://users.livejournal.com/_winnie/433617.html?view=5691601

Если коротко: gcc для #pragma once использует не путь к файлу, а его атрибуты (размер и время) и содержимое.
Это он так борется с проблемой алиасов.
  Undefined! Undefined!
// a.h
#pragma once
x++;

// b.h
#pragma once
x++;

// main.cc
int main()
{
  int x = 0;
#include "a.h"
#include "b.h"
  return x;
}

Если a.h и b.h имеют одинаковое время, то x=1, иначе x=2.


Более подробно — см. жж winnie.
Перекуём баги на фичи!
Re: #pragma twice
От: Muxa  
Дата: 23.07.14 05:14
Оценка:
А в чем была проблема с включением файла по симлинку/хардлинку в gcc?
Re[2]: #pragma twice
От: Кодт Россия  
Дата: 23.07.14 07:50
Оценка: 6 (2)
Здравствуйте, Muxa, Вы писали:

M>А в чем была проблема с включением файла по симлинку/хардлинку в gcc?


Если к одному файлу можно добраться двумя разными путями. Например,
/some/MyCoolLib/include/mycool/foo.h
/some/MyCoolLib-1.2.3/include/mycool/foo.h
где версия 1.2.3 является актуальной.

То есть, хаотичное подключение в одном проекте (в разных единицах компиляции) одного и того же по содержанию foo.h из разных каталогов не является нарушением ODR.
Но может случиться так, что
/some/AnotherLib/include/another/bar.h
явно подключает хедер
#include "../MyCoolLib/include/mycool/foo.h"

тогда как в других местах все делают в расчёте на правильные конфиги
#include <mycool/foo.h>
// и тут внезапно встречается
#include <another/bar.h>


Инклуд-гарды от такой проблемы спасают, но они должны быть уникальны во всём проекте.
Опять же, #pragma once компактнее, чем три строки с двумя одинаковыми идентификаторами (с риском опечататься и #ifndef ONE / #define ANOTHER)


Есть и ещё одна подводная грабля, а именно, препроцессорная магия. Причём, казалось бы, невинная (не тот ад и трэш, который делает бизон
Автор: GhostCoders
Дата: 18.07.14
)
Даже если хедеры бинарно совпадают, у них могут быть разные зависимости:
/site1/foo.h — #include "./bar.h"
/site1/bar.h — нечто специфичное для site1

/site2/foo.h — линк или копия /site1/foo.h
/site2/bar.h — совершенно другое содержимое, специфичное уже для site2

/altogether/all.h — #include <site1/foo.h> и <site2/foo.h>

Тут уже обычные гарды не прокатят, а прагма может коварно сломаться.
Перекуём баги на фичи!
Re[3]: #pragma twice
От: Mr.Delphist  
Дата: 23.07.14 08:42
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Но может случиться так, что

К>/some/AnotherLib/include/another/bar.h
К>явно подключает хедер
К>
К>#include "../MyCoolLib/include/mycool/foo.h"
К>

К>тогда как в других местах все делают в расчёте на правильные конфиги
К>
К>#include <mycool/foo.h>
К>// и тут внезапно встречается
К>#include <another/bar.h>
К>


Ну, тут ИМХО ничего не поможет, "когда в товарищах согласья нет". Я сам, конечно, не испытываю бешеного восторга от этой include-магии, но мы имеем то, что имеем, и если взялся за плюсы, то играй по их правилам.
Re[4]: #pragma twice
От: Кодт Россия  
Дата: 23.07.14 09:31
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Ну, тут ИМХО ничего не поможет, "когда в товарищах согласья нет". Я сам, конечно, не испытываю бешеного восторга от этой include-магии, но мы имеем то, что имеем, и если взялся за плюсы, то играй по их правилам.


Как раз тут поможет старый добрый инклуд-гард.
Нельзя сказать, что это хорошо, потому что двойное включение — это гарантированный слом компиляции (и ибо вотще, надо наводить порядок в коде), а тихое включение потенциально не той версии — это нарушение ODR.
Перекуём баги на фичи!
Re: #pragma twice
От: Abyx Россия  
Дата: 23.07.14 09:45
Оценка: -1
Здравствуйте, Кодт, Вы писали:

К>Если коротко: gcc для #pragma once использует не путь к файлу, а его атрибуты (размер и время) и содержимое.


классический #ifndef X/#define X
дает точно такой же эффект, за исключением того что не учитывает время файла.
— путь к файлу игнорируется, проверяется только содержимое
In Zen We Trust
Re: #pragma twice
От: denisko http://sdeniskos.blogspot.com/
Дата: 23.07.14 10:01
Оценка:
Здравствуйте, Кодт, Вы писали:

К>http://users.livejournal.com/_winnie/433617.html?view=5691601


К>Если коротко: gcc для #pragma once использует не путь к файлу

Это разумно если следовать правилу один
Хидер — один класс. Тогда внутрях они будут разделяться все равно по имени. Вопрос в том принтмаешь ли ты этот стиль кодирования или нет
<Подпись удалена модератором>
Re: #pragma twice
От: Erop Россия  
Дата: 24.07.14 11:32
Оценка:
Здравствуйте, Кодт, Вы писали:


К>Более подробно — см. жж winnie.


Вот же козлы. Правда тот, кто не пишет комментариев и вообще шапки файлов -- ССЗБ
А #pragma once в стандарте есть?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 11:36
Оценка: 2 (1)
Здравствуйте, Кодт, Вы писали:

К>Инклуд-гарды от такой проблемы спасают, но они должны быть уникальны во всём проекте.


Так же, как и имена классов, например.

К>Опять же, #pragma once компактнее, чем три строки с двумя одинаковыми идентификаторами (с риском опечататься и #ifndef ONE / #define ANOTHER)


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

К>Есть и ещё одна подводная грабля, а именно, препроцессорная магия. Причём, казалось бы, невинная (не тот ад и трэш, который делает бизон
Автор: GhostCoders
Дата: 18.07.14
)

К>Даже если хедеры бинарно совпадают, у них могут быть разные зависимости:
К>/site1/foo.h — #include "./bar.h"
К>/site1/bar.h — нечто специфичное для site1


IMHO, это нарушение ODR...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 11:38
Оценка:
Здравствуйте, Abyx, Вы писали:

A>дает точно такой же эффект, за исключением того что не учитывает время файла.

A>- путь к файлу игнорируется, проверяется только содержимое

Обычно гарды если и не гарантированно уникальны на проект, то, как минимум, в них подмешивают имена файлов/классов...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: #pragma twice
От: Кодт Россия  
Дата: 24.07.14 12:10
Оценка:
Здравствуйте, Erop, Вы писали:

К>>Инклуд-гарды от такой проблемы спасают, но они должны быть уникальны во всём проекте.

E>Так же, как и имена классов, например.

Не совсем. Есть несколько способов разрулить идентификаторы.
— static для переменных и функций, namespace{} для всех, включая классы, — чтобы не злить линкера
— формировать имя из макроса, данного извне
namespace MYLIB_AUX {
  class PP_CAT(MYLIB,_Foo) { ..... };
}

— нахлобучивать namespace NS{} извне, — как это сделано, например, для <cstdio>
namespace mylib_aux {
#include <naked.h>
}

Это то, что сразу приходит в голову.

К>>Опять же, #pragma once компактнее, чем три строки с двумя одинаковыми идентификаторами (с риском опечататься и #ifndef ONE / #define ANOTHER)


E>А вообще-то автоматическое прописывание гардов при помощи макросни редактора или скриптов -- рулит

E>Ну и уникальность гардов в проекте тогда можно автоматически проверять...

Определённая культура всё равно нужна.
Если у тебя куча библиотек с хедерами, и в каждой из них есть свой utils.h или config.h ...
Особенно, если библиотеки сторонние...


К>>Есть и ещё одна подводная грабля, а именно, препроцессорная магия. Причём, казалось бы, невинная (не тот ад и трэш, который делает бизон
Автор: GhostCoders
Дата: 18.07.14
)

К>>Даже если хедеры бинарно совпадают, у них могут быть разные зависимости:
К>>/site1/foo.h — #include "./bar.h"
К>>/site1/bar.h — нечто специфичное для site1

E>IMHO, это нарушение ODR...


С чего бы это вдруг?
/* driver.h */
#include "./driver_config.h" /* #define DRIVER_NAME your_driver_name_goes_here и т.п. полезняшки */
void PP_CAT(init_,DRIVER_NAME) (void);
void PP_CAT(done_,DRIVER_NAME) (void);
int  PP_CAT(call_,DRIVER_NAME) (char* cmd);


Конечно, эту магию можно и нужно переделывать, чтобы она была и красивее, и устойчивее к тонкостям препроцессора, — но, тем не менее...
Перекуём баги на фичи!
Re[5]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 13:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Это то, что сразу приходит в голову.

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

К>Определённая культура всё равно нужна.

Это таки да.
Но такие сложные замуты с хедерами, как ты показал, без "определённой культуры" вообще лучше бы не мутить, если честно
К>Если у тебя куча библиотек с хедерами, и в каждой из них есть свой utils.h или config.h ...
К>Особенно, если библиотеки сторонние...

Ну, заверни в изолирующий слой какой, например.
Но gcc со своим подходом всё равно козлы!

E>>IMHO, это нарушение ODR...


К>С чего бы это вдруг?


Ну смотри,
// a.h

struct params {
    int DefaultId;
    std::string Text;
};


// b.h

struct params {
    std::string Text;
    int DefaultId;
};


// foo.h

inline int foo( const params& p )
{
    const int realId = SomeStaticTable.FindId( p.Text );
    return realId != NotFound ? realId : p.DefaultId;
}


ну и где-то в коде у нас
#include "a.h"
include "foo.h"
а где-то
#include "b.h"
include "foo.h"



Как думаешь, с ODR тут всё ok?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: #pragma twice
От: Кодт Россия  
Дата: 24.07.14 15:16
Оценка:
Здравствуйте, Erop, Вы писали:

К>>Если у тебя куча библиотек с хедерами, и в каждой из них есть свой utils.h или config.h ...

К>>Особенно, если библиотеки сторонние...

E>Ну, заверни в изолирующий слой какой, например.


Для хедер-онли библиотек особо не позаворачиваешь. Придётся патчить.
Причём не факт, что где-нибудь не лежит закладка на конкретное имя гарда, — как это сделал бизон, и как тут уже коллега плакался (потому что у гуся и вижела гард для <stdlib.h> по-разному называется)

E>Но gcc со своим подходом всё равно козлы!

не козлы, а бараны.

E>>>IMHO, это нарушение ODR...

К>>С чего бы это вдруг?

E>Ну смотри,

<...>
E>Как думаешь, с ODR тут всё ok?..

Не. Как нарушать ODR — это я знаю и умею. И как не нарушать — тоже.
Я показал более-менее реалистичный пример, когда одинаковые файлы с разными зависимостями нужно загрузить вместе, но из-за ложного срабатывания прагмы это обломится.

Может быть, это даже не магия с именами, а скелет плагина
// plugin_all.h
#pragma once

#include "./plugin_class.h"
#include "./plugin_factory.h"
#include "./plugin_tests.h"

где в зависимостях уже будут лежать class foo_plugin, class foo_factory и т.д.
Перекуём баги на фичи!
Re[7]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 16:20
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Для хедер-онли библиотек особо не позаворачиваешь. Придётся патчить.

Во-первых, почему?
Во-вторых, ечли даже и патчить, но автоматом, то проблема невелика есть...

К>Причём не факт, что где-нибудь не лежит закладка на конкретное имя гарда, — как это сделал бизон, и как тут уже коллега плакался (потому что у гуся и вижела гард для <stdlib.h> по-разному называется)

Тоже автомат тут помогает, ну и потом мало ли какие говнобиблиотеки закладываются на неспециализированное или неопределённое поведение? Не надо использовать говно-код, особенно если ты не можешь его поправить

Да, это всё равно не отменяет моего мнения, что в этом вопросе гцц — козлы.

E>>Но gcc со своим подходом всё равно козлы!

К>не козлы, а бараны.
Мне кажется, что в данном случае речь иджёт о ГМО, сочетающем свойства обеих видов
Я так думаю, что придумали они это сдуру, а внедрили и сохраняют потому, что нетривильный вендор-лок


К>Не. Как нарушать ODR — это я знаю и умею. И как не нарушать — тоже.

К>Я показал более-менее реалистичный пример, когда одинаковые файлы с разными зависимостями нужно загрузить вместе, но из-за ложного срабатывания прагмы это обломится.
А какая разница с точки зрения ОДР в одинаковых файлах повторяется определение или в разных?
Любык два поределения объекта, если вообще для таких объектов ОДР допускает, что бы их было больше одного, должны быть ЭКВИВАЛЕНТНЫ жеж?..
Или речь идёт не о С++ объектах, а о препроцессороной магии какой?

К>Может быть, это даже не магия с именами, а скелет плагина

К>
К>// plugin_all.h
К>#pragma once

К>#include "./plugin_class.h"
К>#include "./plugin_factory.h"
К>#include "./plugin_tests.h"
К>

К>где в зависимостях уже будут лежать class foo_plugin, class foo_factory и т.д.
Ну это ты ССЗБ, IMHO, это довольно опасная идея, класть в разные места файлы с одним именем, и при этом гарантированно неэквивалентным содержимым. Фиг его знает что откуда подключат
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: #pragma twice
От: Ops Россия  
Дата: 24.07.14 16:46
Оценка: 10 (1)
Здравствуйте, Erop, Вы писали:

E>А #pragma once в стандарте есть?


Не а.
16.6 Pragma directive [cpp.pragma]
1
A preprocessing directive of the form
# pragma pp-tokens opt new-line
causes the implementation to behave in an implementation-defined manner. The behavior might cause
translation to fail or cause the translator or the resulting program to behave in a non-conforming manner.
Any pragma that is not recognized by the implementation is ignored.

Это все что есть про прагму.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[8]: #pragma twice
От: Кодт Россия  
Дата: 24.07.14 16:57
Оценка:
Здравствуйте, Erop, Вы писали:

E>>>Но gcc со своим подходом всё равно козлы!

К>>не козлы, а бараны.
E>Мне кажется, что в данном случае речь иджёт о ГМО, сочетающем свойства обеих видов
E>Я так думаю, что придумали они это сдуру, а внедрили и сохраняют потому, что нетривильный вендор-лок

Что за вендор-лок?

E>Любык два поределения объекта, если вообще для таких объектов ОДР допускает, что бы их было больше одного, должны быть ЭКВИВАЛЕНТНЫ жеж?..

E>Или речь идёт не о С++ объектах, а о препроцессороной магии какой?

О препроцессорной, и даже не магии, а макро-файлах.
Да, это ССЗБ, но приём известный.
Перекуём баги на фичи!
Re[9]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 17:07
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Что за вендор-лок?


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

К>Да, это ССЗБ, но приём известный.

Дык в С/С++ мире грабель известных конструкций ещё больше, чем известных систем для стрельбы по ногам
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: #pragma twice
От: ononim  
Дата: 24.07.14 17:46
Оценка: +1
К>Если коротко: gcc для #pragma once использует не путь к файлу, а его атрибуты (размер и время) и содержимое.
К>Это он так борется с проблемой алиасов.

А почему не inode? (а под виндой есть fileid)
Как много веселых ребят, и все делают велосипед...
Re[2]: #pragma twice
От: Erop Россия  
Дата: 24.07.14 18:52
Оценка:
Здравствуйте, ononim, Вы писали:


O>А почему не inode? (а под виндой есть fileid)


Дык подмапировать могут чегой-нибудь рассово-чуждое и привет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: #pragma twice
От: ononim  
Дата: 24.07.14 21:59
Оценка: +1
O>>А почему не inode? (а под виндой есть fileid)
E>Дык подмапировать могут чегой-нибудь рассово-чуждое и привет...
Для рассово-чуждых можно хэшировать файл целиком, сравнив предварительно путь на не-совпадение.
Но, я так понимаю, любители сфероидальных архитектур не обращают внимания на жалобы жителей домов на то, что их жилища постоянно катаются по улицам, что приводит к различным неудобствам. Зато — идеальная сфера.
Как много веселых ребят, и все делают велосипед...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.