Приведение указателя между эквивалентными классами
От: Tom Россия http://www.RSDN.ru
Дата: 02.02.04 10:03
Оценка:
Насколько сабж легален?

Т.ь допустим

struct foo1
{
    int i_;
}

struct foo2
{
    int i_;
}

foo1 * p = reinterpret_cast<foo1*>(new foo2());


Ы?
... << RSDN@Home 1.1.0 stable >>
Народная мудрось
всем все никому ничего(с).
Re: Приведение указателя между эквивалентными классами
От: Анатолий Широков СССР  
Дата: 02.02.04 10:14
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Насколько сабж легален?


Tom>Т.ь допустим


Tom>
Tom>struct foo1
Tom>{
Tom>    int i_;
Tom>}

Tom>struct foo2
Tom>{
Tom>    int i_;
Tom>}

Tom>foo1 * p = reinterpret_cast<foo1*>(new foo2());
Tom>


Tom>Ы?


Понятия "эквивалентного класса" не существует. Так что, то, что Вы привели, грязный хак.
Re[2]: Приведение указателя между эквивалентными классами
От: Lorenzo_LAMAS  
Дата: 02.02.04 10:28
Оценка:
Вообще говоря, есть понятие layout-compatible POD структур, которыми являются структуры Tom'а. Только вот я что-то не нашел по поводу легальности преобразования указателей.
Of course, the code must be complete enough to compile and link.
Re[3]: Приведение указателя между эквивалентными классами
От: Vamp Россия  
Дата: 02.02.04 10:31
Оценка:
L_L>Вообще говоря, есть понятие layout-compatible POD структур, которыми являются структуры Tom'а. Только вот я что-то не нашел по поводу легальности преобразования указателей.
Как известно, единственное легальное действие с указателем после преобразования — обратное преобразование.
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Приведение указателя между эквивалентными классами
От: Анатолий Широков СССР  
Дата: 02.02.04 10:33
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Вообще говоря, есть понятие layout-compatible POD структур, которыми являются структуры Tom'а. Только вот я что-то не нашел по поводу легальности преобразования указателей.


Да, но контроля со стороны компилятора никакого, ибо reinterpret_cast. В один прекрасный момент foo1 или foo2 станет не POD-ом и система загремит под фанфары.
Re[4]: Приведение указателя между эквивалентными классами
От: Lorenzo_LAMAS  
Дата: 02.02.04 10:36
Оценка:
АШ>Да, но контроля со стороны компилятора никакого, ибо reinterpret_cast. В один прекрасный момент foo1 или foo2 станет не POD-ом и система загремит под фанфары.

А вот этого никто не говорил, что они должны стать не под типом. В вопросе под.
Of course, the code must be complete enough to compile and link.
Re[5]: Приведение указателя между эквивалентными классами
От: Анатолий Широков СССР  
Дата: 02.02.04 10:38
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

АШ>>Да, но контроля со стороны компилятора никакого, ибо reinterpret_cast. В один прекрасный момент foo1 или foo2 станет не POD-ом и система загремит под фанфары.


L_L>А вот этого никто не говорил, что они должны стать не под типом. В вопросе под.


Не в вопросе, а в примере.
Re[6]: Приведение указателя между эквивалентными классами
От: Lorenzo_LAMAS  
Дата: 02.02.04 10:41
Оценка:
АШ>Не в вопросе, а в примере.

В каком????
Of course, the code must be complete enough to compile and link.
Re[7]: Приведение указателя между эквивалентными классами
От: Анатолий Широков СССР  
Дата: 02.02.04 10:43
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

АШ>>Не в вопросе, а в примере.


L_L>В каком????


Оригинальный вопрос звучал так: Приведение указателя между эквивалентными классами. Насколько сабж легален?

О поде ни слова. А пример да, он с подами.
Re[3]: Приведение указателя между эквивалентными классами
От: Павел Кузнецов  
Дата: 02.02.04 11:23
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

LL> Вообще говоря, есть понятие layout-compatible POD структур,

LL> которыми являются структуры Tom'а. Только вот я что-то не нашел
LL> по поводу легальности преобразования указателей.

Для layout compatible POD-структур все должно быть в порядке, т.к. они должны
иметь идентичное представление. Также смотри:

C.1.2 clause 3/5 (3.9)

Change: C allows “compatible types” in several places, C++ does not
For example, otherwise-identical struct types with different tag names
are “compatible” in C but are distinctly different types in C++.
Rationale: Stricter type checking is essential for C++.
Effect on original feature: Deletion of semantically well-defined feature.
Difficulty of converting: Semantic transformation. The “typesafe linkage”
mechanism will find many, but not all, of such problems. Those problems
not found by typesafe linkage will continue to function properly, according
to the “layout compatibility rules” of this International Standard.
How widely used: Common.

Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Приведение указателя между эквивалентными классами
От: Lorenzo_LAMAS  
Дата: 02.02.04 11:33
Оценка:
Т.е. ответ Тому на его вопрос да, легально (для такого примера), ответ А.Ш. нет, не хак. Так?
Of course, the code must be complete enough to compile and link.
Re[5]: Приведение указателя между эквивалентными классами
От: Павел Кузнецов  
Дата: 02.02.04 11:42
Оценка: 11 (2)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

LL> Т.е. ответ Тому на его вопрос да, легально (для такого примера),

LL> ответ А.Ш. нет, не хак. Так?

Не вполне... Для пущей строгости Тому надо еще extern "C" добавить.
А в остальном, как я понимаю, — да.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Приведение указателя между эквивалентными классами
От: Анатолий Широков СССР  
Дата: 02.02.04 12:04
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Т.е. ответ Тому на его вопрос да, легально (для такого примера), ответ А.Ш. нет, не хак. Так?


Отлично, я не против — не хак, тогда почему не легализировать вот это

foo1 *p1 = new foo2;


вместо "страшного" reinterpret_cast?

И еще, как проверить, что два pod-a layout совместимы?
И еще еще, где на практике может понадобиться эта возможность?

Спасибо.
Re[6]: Приведение указателя между эквивалентными классами
От: Lorenzo_LAMAS  
Дата: 02.02.04 12:09
Оценка:
да вообще-то это был просто вопрос, это не какая-то важная фича которой очень хочется пользоваться. Павел вроде все объяснил уже. Т.е. если структуры не будут extern "C" то как Вы и сказали — хак.
Of course, the code must be complete enough to compile and link.
Re: Приведение указателя между эквивалентными классами
От: Denwer Россия  
Дата: 03.02.04 07:11
Оценка:
Здравствуйте, Tom, Вы писали:

Видел в книжке одной (Арчер вроде, это которая по Visual C++ 7), так он там вообще указатель CFormView приводит к CDialog, для того что бы поюзать некоторые диалоговские функции. Вот так вот. Хотя там были полиморфные классы. Я конечно понимаю что так нельзя, но все же автор то известный.
Re[2]: Приведение указателя между эквивалентными классами
От: Павел Кузнецов  
Дата: 03.02.04 07:45
Оценка:
Здравствуйте, Denwer, Вы писали:

D> Видел в книжке одной (Арчер вроде, это которая по Visual C++ 7), так он

D> там вообще указатель CFormView приводит к CDialog, для того что бы поюзать
D> некоторые диалоговские функции.

Вся архитектура MFC на таком безобразии завязана. Это вольности, допустимые
для конкретной реализации, но не в общем случае.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Приведение указателя между эквивалентными классами
От: Аноним  
Дата: 03.02.04 08:14
Оценка: 1 (1) +1
ПК>Вся архитектура MFC на таком безобразии завязана. Это вольности, допустимые
ПК>для конкретной реализации, но не в общем случае.

Самое забавное, это оправдывать такие хаки известностью автора. Дурь написана, но автор то известный!!!
Re[6]: Приведение указателя между эквивалентными классами
От: Dmi3evS Россия http://dmi3s.blogspot.com/
Дата: 04.02.04 21:06
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Не вполне... Для пущей строгости Тому надо еще extern "C" добавить.

Павел, я попытался убедиться по стандарту, что это действительно так, и не сумел.
Не могли бы Вы повторить детально ход Ваших рассуждений?

Очевидно, что, вследствие 9.2/17, запись
foo2* p = reinterpret_cast<foo2*>( reinterpret_cast<int*>( &foo1_instance ) );

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

Однако я не нашел, как доказать валидность преобразования
foo2* p = reinterpret_cast<foo2*>( &foo1_instance );

независимо от того, extern "C" типы foo1 и foo2, или нет.

Согласно 5.2.10/7, результат такого преобразования "is unspecified".
Более того, хотя стандарт четко определяет, что такое "layout-compatible", мне не вполне понятно, для чего вообще может понадобиться знание того, что два типа layout-compatible.

Скажем, из стандарта не очевидно, что преобразование
union foo_u {
  foo1 f1;
  foo2 f2;
};
foo2* p = &(reinterpret_cast<foo_u*>( &foo1_instance )->f2);

валидно.

С уважением,
Сергей Дмитриев
Re[7]: Приведение указателя между эквивалентными классами
От: Павел Кузнецов  
Дата: 10.02.04 09:35
Оценка: 2 (2)
Здравствуйте, Dmi3evS, Вы писали:

ПК>> Не вполне... Для пущей строгости Тому надо еще extern "C" добавить.


D> Павел, я попытался убедиться по стандарту, что это действительно так,

D> и не сумел. Не могли бы Вы повторить детально ход Ваших рассуждений?

Вообще, ни определение layout-compatible структур, ни допустимые с ними операции
в стандарте не проработаны в достаточной степени для каких бы то ни было
"строгих" рассуждений. Например, до TC1 в определении layout-compatible структур
требовалось даже, чтобы структуры имели одно и то же число функций-членов
и статических членов:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#190

Тем не менее, с практической точки зрения, можно ожидать, что некоторые вещи
с layout-compatible структурами работать будут. В частности:
С любой структурой допускается работать через указатель. В месте использования
указателя может не быть известно, находится ли данная структура в объединении,
или нет. Фактически все это означает, что скопировав каким-то образом значение
указателя на одну структуру в указатель на layout-compatible структуру, мы можем
ожидать, что работая через новый указатель, не получим никаких сюрпризов.

Однако есть по меньшей мере два "но":

Как видно из ранее процитированного фрагмента (ненормативной) части стандарта
понятие layout-compatible структур было оставлено для совместимости с C. Для
удобства я еще раз приведу этот фрагмент:
C.1.2 clause 3/5 (3.9)

Change: C allows “compatible types” in several places, C++ does not.
For example, otherwise-identical struct types with different tag names are
“compatible” in C but are distinctly different types in C++.
Rationale: Stricter type checking is essential for C++.
Effect on original feature: Deletion of semantically well-defined feature.
Difficulty of converting: Semantic transformation. The “typesafe linkage”
mechanism will find many, but not all, of such problems. Those problems not found
by typesafe linkage will continue to function properly, according to the “layout
compatibility rules” of this International Standard.
How widely used: Common.

Т.е. несовместимости типов, не обнаруживаемые на стадии компоновки, по задумке
комитетчиков должны продолжать работать, как и в C. При компоновке не будут
различаться структуры, объявленные как extern "C". Поэтому, держа в голове тот
самый гипотетический случай "навороченных" run-time проверок, я предположил,
что меньшим "хаком" будет преобразование extern "C" layout-compatible структур.

reinterpret_cast — самое слабое место, если рассуждать "строго". Но тут спасает,
что реализации придется уж очень сильно извернуться, чтобы поломать наши примеры.
В самом деле, учитывая идентичность представлений значений указателей на layout-
compatible типы, ничем кроме "диверсии" со стороны разработчиков компилятора,
модификацию этого значения при подобном преобразовании я лично объяснить не могу.

Итого: строго говоря, конечно, стандарт не дает прямых гарантий, что исходный,
или модифицированный примеры будут работать, но, полагаю, что это будет верным
для всех существующих реализаций. Также, из соображений совместимости с C,
маловероятно, что модифицированный (с extern "C") пример когда-нибудь перестанет
работать. Т.е. если под "хаком" понимать практическую работоспособность, это не
"хак"; если абсолютное соответствие букве стандарта — безусловно "хак".

D> Очевидно, что, вследствие 9.2/17, запись

D>
 D> foo2* p = reinterpret_cast<foo2*>( reinterpret_cast<int*>( &foo1_instance ) );
 D>

D> вполне валидна и позволяет гарантированно работать с первым элементом
D> совместимых структур.

Подобный "финт" гарантирует работоспособность примера немногим в большей степени,
чем "простой" reinterpret_cast. В самом деле, стандарт не дает никаких гарантий,
что преобразования int* -> foo2* и int* -> foo1* будут давать одинаковые значения
указателей. Естественно, что "испортить" этот пример, также как и "прямой"
reinterpret_cast, разработчики компилятора могут только предпринимая сознательные
усилия. Впрочем, т.к. никаких причин для таких их действий не видно, ожидать, что
они сделают такую пакость, не приходится

D> Согласно 5.2.10/7, результат такого преобразования "is unspecified".

D> Более того, хотя стандарт четко определяет, что такое "layout-compatible",
D> мне не вполне понятно, для чего вообще может понадобиться знание того, что
D> два типа layout-compatible.

Как упоминалось выше, в нормативной части прямо layout-compatible типы
используются для описания семантики объединений, совместимых с C.

D> Скажем, из стандарта не очевидно, что преобразование

D>
 D> union foo_u {
 D>   foo1 f1;
 D>   foo2 f2;
 D> };
 D> foo2* p = &(reinterpret_cast<foo_u*>( &foo1_instance )->f2);
 D>

D> валидно.

Строго говоря, невалидно. Имхо, даже менее валидно, чем оригинальный пример
(если, конечно, рассуждения о степени валидности здесь уместны ), т.к. доступ
к объекту типа foo1 осуществляется через указатель типа foo_u, который даже
не является layout-compatible с foo1. И, если компилятор будет поддерживать
run-time проверки "кошерности" доступа, здесь, имхо, он как раз и должен
будет "выстрелить".
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.