Безопасно ли приводить UINT <--> void* ??
От: Аноним  
Дата: 27.04.04 06:49
Оценка:
Вопрос вот в чем.
Мне необходимо для каждого объекта уникальное имя, по которому можно быстро достать сам объект. Я поступаю так:

UINT name = reinterpret_cast<UINT>(this);

а потом так же перевожу это имя в указатель.
Вот вопрос и заключается в том — безопасно ли это? То есть можно ли быть уверенным, что полученное таким образом name точно переведется назад в нужный указатель? Вопрос возник потому, что перешел с шестой на седьмую VC, и седьмая вывалила ворнинги. Заранее спасибо
Re: Безопасно ли приводить UINT <--> void* ??
От: Alex Fedotov США  
Дата: 27.04.04 06:55
Оценка: 26 (3)
Здравствуйте, Аноним, Вы писали:

А>Вопрос вот в чем.

А>Мне необходимо для каждого объекта уникальное имя, по которому можно быстро достать сам объект. Я поступаю так:

А>UINT name = reinterpret_cast<UINT>(this);


А>а потом так же перевожу это имя в указатель.

А> Вот вопрос и заключается в том — безопасно ли это?

Вообще говоря — нет. Разрядность UINT может быть меньше, чем разрядность void *. Это, кстати, имеет место на платформе Win64, о чем и предупреждает VC7.

Безопасным с точки зрения Win64 будет преобразование к UINT_PTR:

UINT_PTR name = reinterperet_cast<UINT_PTR>(this);


UINT_PTR определен как целочисленный тип с такой же разрядностью как у указателя (32 бита на Win32 и 64 — на Win64).
-- Alex Fedotov
Re[2]: Безопасно ли приводить UINT <--> void* ??
От: Bell Россия  
Дата: 27.04.04 06:58
Оценка: 5 (1)
Здравствуйте, Alex Fedotov, Вы писали:

AF>Здравствуйте, Аноним, Вы писали:


А>>Вопрос вот в чем.

А>>Мне необходимо для каждого объекта уникальное имя, по которому можно быстро достать сам объект. Я поступаю так:

А>>UINT name = reinterpret_cast<UINT>(this);


А>>а потом так же перевожу это имя в указатель.

А>> Вот вопрос и заключается в том — безопасно ли это?

Безопасно при условии, что UINT имеет достаточный размер. Подробнее — 5.2.10/4, 5.2.10/5
Любите книгу — источник знаний (с) М.Горький
Re[2]: Безопасно ли приводить UINT <--> void* ??
От: Аноним  
Дата: 27.04.04 07:00
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Вообще говоря — нет. Разрядность UINT может быть меньше, чем разрядность void *. Это, кстати, имеет место на платформе Win64, о чем и предупреждает VC7.


AF>Безопасным с точки зрения Win64 будет преобразование к UINT_PTR:


AF>
AF>UINT_PTR name = reinterperet_cast<UINT_PTR>(this);
AF>


AF>UINT_PTR определен как целочисленный тип с такой же разрядностью как у указателя (32 бита на Win32 и 64 — на Win64).


А будут глюки, если скомпилировать на Win64 или если будет работать программа на Win64, даже если скомплировали на win32? То есть если стопроцентно компилить на 32, то будет работать везде?
Re: Безопасно ли приводить UINT <--> void* ??
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 27.04.04 07:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос вот в чем.

А>Мне необходимо для каждого объекта уникальное имя, по которому можно быстро достать сам объект. Я поступаю так:

А>UINT name = reinterpret_cast<UINT>(this);


А>а потом так же перевожу это имя в указатель.


Лучше пользоваться какой нибудь оболочкой над reinterpret_cast, например:
template<class T1, class T2>
T1 safe_reinterpret_cast(const T2 &X)
{
    STATIC_ASSERT(sizeof(T1)>=sizeof(T2));
    return reinterpret_cast<T1>(X);
}
...
UINT name = safe_reinterpret_cast<UINT>(this);


Здесь STATIC_ASSERT(x) это макрос, который генерирует ошибку компиляции если условие x ложно. Например так:
#define STATIC_ASSERT(x) typedef int static_assert_error[(x) ? 1 : -1]


Или готовые реализации:
BOOST_STATIC_ASSERT.

Тогда, при переходе на другую платформу, на которой sizeof(this)>sizeof(UINT) получим ошибку компиляции.
getboost.codeplex.com
citylizard.codeplex.com
Re[2]: Безопасно ли приводить UINT <--> void* ??
От: Аноним  
Дата: 27.04.04 07:24
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:
AF>Безопасным с точки зрения Win64 будет преобразование к UINT_PTR:

Дело в том, что я это имя засовываю в стороннюю библиоеку (glLoadName в OpenGL), которая требует UINT. Не юзать же map для этого — медленный доступ тогда будет
Re[2]: Безопасно ли приводить UINT <--> void* ??
От: Аноним  
Дата: 27.04.04 07:30
Оценка:
Здравствуйте, sergey_shandar, Вы писали:

_>Лучше пользоваться какой нибудь оболочкой над reinterpret_cast, например:

_>
_>template<class T1, class T2>
_>T1 safe_reinterpret_cast(const T2 &X)
_>{
_>    STATIC_ASSERT(sizeof(T1)>=sizeof(T2));
_>    return reinterpret_cast<T1>(X);
_>}
_>...
_>UINT name = safe_reinterpret_cast<UINT>(this);
_>

_>Тогда, при переходе на другую платформу, на которой sizeof(this)>sizeof(UINT) получим ошибку компиляции.

Я уже задал этот вопрос но повторюсь. Будет ли работать эта программа, скомпилированная на 32 разр платфоме, на 64разрядной? ведб насколько я понимаю, всякие int-ы — это штучки компиляьтора, а вот адресация памяти -это же уже не компиляторная вещь. Или я не прав?
Re[3]: Безопасно ли приводить UINT <--> void* ??
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 27.04.04 07:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я уже задал этот вопрос но повторюсь. Будет ли работать эта программа, скомпилированная на 32 разр платфоме, на 64разрядной?

Хоть 1024 разрядная платформа, но если программа уже откомпилированна как 32 разрядная, значит и будет работать как 32 разрядная; либо не будет работать вообще, например, если MS решит что 32 разрядный режим больше не нужен.
getboost.codeplex.com
citylizard.codeplex.com
Re[3]: Безопасно ли приводить UINT <--> void* ??
От: Mr. None Россия http://mrnone.blogspot.com
Дата: 27.04.04 08:03
Оценка:
Здравствуйте, Bell, Вы писали:

B>Безопасно при условии, что UINT имеет достаточный размер. Подробнее — 5.2.10/4, 5.2.10/5


Вопрос примерно из той же оперы... Где-нибудь в стандарте гарантировано, что покрайней мере один целый тип должен совпадать по размерам с указателем? Если честно, то я не нашёл .
VC7.0 выкидывает предупреждения и при попытке преобразовать указатель к long`у, иногда это приходится делать, особенно на нижних архитектурных слоях приложения. Неужели в Win64 long так и останется 32-ух разрядным и придётся пользоваться их нестандартным __int64?!!! Это же сколько программ упадут в одночасье!!!!
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re: Безопасно ли приводить UINT <--> void* ??
От: Евгений Коробко  
Дата: 27.04.04 08:30
Оценка:
Есть ещё один момент. При множественном наследовании пробразование указателей к базовому классу может менять физическое значение указателя.
Posted via RSDN NNTP Server 1.8
Евгений Коробко
Re: Безопасно ли приводить UINT <--> void* ??
От: achp  
Дата: 27.04.04 09:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>UINT name = reinterpret_cast<UINT>(this);


На платформе Windows нынче определен тип UINT_PTR (т. е., целый тип, достаточный для вмещения указателя).
Re[4]: Безопасно ли приводить UINT <--> void* ??
От: Павел Кузнецов  
Дата: 27.04.04 16:43
Оценка:
> Вопрос примерно из той же оперы... Где-нибудь в стандарте гарантировано, что покрайней мере один целый тип должен совпадать по размерам с указателем? Если честно, то я не нашёл

Непосредственно таких гарантий стандарт C++ не дает, хотя с практической точки зрения можно считать, что такими типами являются std::size_t и std::ptrdiff_t.

Стандарт C 99 вводит соответствущие типы intptr_t и uintptr_t:

7.18.1.4
The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

intptr_t

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:
uintptr_t

These types are optional.

Можно ожидать, что в следующей версии C++ они будут адаптированы как std::intptr_t и std::uintptr_t.

> VC7.0 выкидывает предупреждения и при попытке преобразовать указатель к long`у, иногда это приходится делать, особенно на нижних архитектурных слоях приложения. Неужели в Win64 long так и останется 32-ух разрядным и придётся пользоваться их нестандартным __int64?


Хорошо ли это, или плохо, но именно так и есть:
http://msdn.microsoft.com/library/en-us/win64/win64/abstract_data_models.asp

Making all data types 64 bits in length would waste space, because most applications do not need the increased size. However, applications do need pointers to 64-bit data, and they need the ability to have 64-bit data types in selected cases. These considerations led the team to select an abstract data model called LLP64 (or P64). In the LLP64 data model, only pointers expand to 64 bits; all other basic data types (integer and long) remain 32 bits in length.


Утешающим фактом можно считать то, что std::size_t и std::ptrdiff_t, скорее всего, будут 64-битными.
Posted via RSDN NNTP Server 1.8
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Безопасно ли приводить UINT <--> void* ??
От: achp  
Дата: 28.04.04 07:35
Оценка: 1 (1) +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Непосредственно таких гарантий стандарт C++ не дает, хотя с практической точки зрения можно считать, что такими типами являются std::size_t и std::ptrdiff_t.


Это почему? Например, вспомним сегментную архитектуру Intel 8086/8088. Указатель (дальний) там 32-битный, но нет смысла делать размеры size_t и ptrdiff_t более чем 16-битными.

ПК>Утешающим фактом можно считать то, что std::size_t и std::ptrdiff_t, скорее всего, будут 64-битными.


Ой, полезут проблемы изо всех щелей...
Re[3]: Безопасно ли приводить UINT <--> void* ??
От: _Winnie Россия C++.freerun
Дата: 28.04.04 08:02
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Дело в том, что я это имя засовываю в стороннюю библиоеку (glLoadName в OpenGL), которая требует UINT. Не юзать же map для этого — медленный доступ тогда будет


Не засовывай указатель, если тебя это волнует. Засовывай индекс в массиве(std::vector ?), в котором лежат все эти указатели....
Можешь забить и все равно класть туда указатель. Сомневаюсь, что эта пргограмма доживет до 64-битной платформы

UINT_PTR проблемы не решит, если надо будет переезать на 64 бита, ибо нет
glLoadName(GLuint_ptr), есть только void glLoadName(GLuint name);
Правильно работающая программа — просто частный случай Undefined Behavior
Re[4]: Безопасно ли приводить UINT <--> void* ??
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 28.04.04 08:10
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Не засовывай указатель, если тебя это волнует. Засовывай индекс в массиве(std::vector ?), в котором лежат все эти указатели....

_W>Можешь забить и все равно класть туда указатель. Сомневаюсь, что эта пргограмма доживет до 64-битной платформы
Доброжелатель или ясновидец?

_W>UINT_PTR проблемы не решит, если надо будет переезать на 64 бита, ибо нет

_W>glLoadName(GLuint_ptr), есть только void glLoadName(GLuint name);
Можно сделать оболочку, которая автоматически выбирает в случае если sizeof(GLuint)<sizeof(HisClass *) то сделать map, иначе можно без map.
getboost.codeplex.com
citylizard.codeplex.com
Re[4]: Безопасно ли приводить UINT <--> void* ??
От: Аноним  
Дата: 28.04.04 08:17
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Сомневаюсь, что эта пргограмма доживет до 64-битной платформы


Почему?
Re[6]: Безопасно ли приводить UINT <--> void* ??
От: Павел Кузнецов  
Дата: 28.04.04 16:27
Оценка:
>> с практической точки зрения можно считать, что такими типами являются std::size_t и std::ptrdiff_t.

> Это почему? Например, вспомним сегментную архитектуру


Семен Семеныч!.. Про архитектуры с неплоской памятью я и забыл... Ну, тогда надо ждать адаптации [u]intptr_t
Posted via RSDN NNTP Server 1.8
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Безопасно ли приводить UINT <--> void* ??
От: Шахтер Интернет  
Дата: 29.04.04 00:33
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>>> с практической точки зрения можно считать, что такими типами являются std::size_t и std::ptrdiff_t.


>> Это почему? Например, вспомним сегментную архитектуру


ПК>Семен Семеныч!.. Про архитектуры с неплоской памятью я и забыл... Ну, тогда надо ждать адаптации [u]intptr_t


А зачем ждать? Вставляем в header system_adapt.h.

typedef  <что-то подходящее>  uintptr_t; 

typedef  <что-то подходящее>  intptr_t;
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[8]: Безопасно ли приводить UINT <--> void* ??
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 29.04.04 02:42
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>
Ш>typedef  <что-то подходящее>  uintptr_t; 

Ш>typedef  <что-то подходящее>  intptr_t; 
Ш>


Насколько я понимаю, теоретически, может быть такое что ничего подходящего нет . А вообще, зачем нужен [u]intptr_t? Вопрос который задали на форуме к [u]intptr_t не имеет никакого отношения, так как Аноним просто хочет запихнуть указатель конкретно в UINT. И я его понимаю: функция принимает UINT, а он хочет запомнить указатель (проблемы дизайна идут в другой раздел). С таким же успехом можно хотеть запихнуть его во float или char[N], так что теперь надо изобретать floatptr_t?. Кто вообще сказал что указатель в общем случае можно представить в виде целого числа? Если Вам нужен тип для хранения указателей, есть void *.
getboost.codeplex.com
citylizard.codeplex.com
Re[9]: Безопасно ли приводить UINT <--> void* ??
От: Шахтер Интернет  
Дата: 29.04.04 03:32
Оценка:
Здравствуйте, sergey_shandar, Вы писали:

_>Здравствуйте, Шахтер, Вы писали:


Ш>>
Ш>>typedef  <что-то подходящее>  uintptr_t; 

Ш>>typedef  <что-то подходящее>  intptr_t; 
Ш>>


_>Насколько я понимаю, теоретически, может быть такое что ничего подходящего нет . А вообще, зачем нужен [u]intptr_t? Вопрос который задали на форуме к [u]intptr_t не имеет никакого отношения, так как Аноним просто хочет запихнуть указатель конкретно в UINT. И я его понимаю: функция принимает UINT, а он хочет запомнить указатель (проблемы дизайна идут в другой раздел). С таким же успехом можно хотеть запихнуть его во float или char[N], так что теперь надо изобретать floatptr_t?. Кто вообще сказал что указатель в общем случае можно представить в виде целого числа? Если Вам нужен тип для хранения указателей, есть void *.


Это скорее уже теоретическая дискуссия пошла. Я собственно согласен, раз есть ситуация, что дан UINT и надо запихать туда указатель, ну что ж, значит надо запихать. Переносимость при этом сужается, ничего не поделаешь. Дешевым методом сделать переносимое решение тут не получится.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.