Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.144.33.41] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здравствуйте!
Несколько раз встречал рекомендацию, что указатель в число, можно приводить через reinterpret_cast, но рекомендуется через static_cast. Решил поправить старый код. Но тут вылезли какие-то ошибки. int a = 0; const int* const p = &a; /* проверка размерности указателя */ static_assert( sizeof( const unsigned long long int ) == sizeof( const void* const ), "check sizeof pointer" ); // работает, но не рекомендуется const unsigned long long int intx = reinterpret_cast< const unsigned long long int >( p ); /* так рекомендуется, но не работает */ const void* const y1 = static_cast< const void* const >( p ); const unsigned long long int y2 = static_cast< const unsigned long long int >( y1 ); Может быть я пропустил какой-то этап? Или это тот самый мифический глюк компилятора? |
Сообщ.
#2
,
|
|
|
Это ?
int a = 0; const int* const p = &a; /* проверка размерности указателя */ // static_assert( sizeof( const unsigned long long int ) == sizeof( const void* const ), "check sizeof pointer" ); // работает, но не рекомендуется // const unsigned long long int intx = reinterpret_cast< const unsigned long long int >( p ); /* так рекомендуется, но не работает */ // const void* const y1 = static_cast< const void* const >( p ); // const unsigned long long int y2 = reinterpret_cast< const unsigned long long int >( y1 ); const unsigned long long int y2 = *static_cast<const unsigned long long int*>(static_cast<const void* const>(&p)); |
Сообщ.
#3
,
|
|
|
Преобразование между целыми и указателями никогда не были стандартизованы. Любые такие касты определяются исключительно реализациями. Именно по этой причине они и осуществляются посредством reinterpret_cast<>, потому как непереносимы. Поэтому ты нигде не мог читать совет по замене их на static_cast<>.
|
Сообщ.
#4
,
|
|
|
Цитата Qraizer @ Поэтому ты нигде не мог читать совет по замене их на static_cast<>. Цитата для преобразования указателей лучше использовать двойной static_cast через void* вместо reinterpret_cast, потому как такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении https://habrahabr.ru/post/106294/ Добавлено А вот в другой статье, действительно, немного иной смысл. Но после неё я и задумался над приведением указателя в число. Цитата Но не все так плохо: Результат преобразования указателя в целочисленный тип зависит от используемой реализации, а значит, именно она и должна описывать его поведение. Если ваша реализация предполагает получение численного значения линейного адреса объекта, на который ссылается указатель, и вы знаете, что работаете на архитектуре с плоской моделью памяти, то выходом будет сравнивать целые значения вместо указателей. Сравнение целых чисел не имеет таких ограничений, как сравнение указателей. https://habrahabr.ru/company/pvs-studio/blog/340458/ Добавлено Цитата ЫукпШ @ Это ? Упс. А я и запамятовал о таком весёлом хаке. Иногда сам делал. А тут даже не подумал применить. Спасибо за идеию! |
Сообщ.
#5
,
|
|
|
Цитата Eric-S @ Читай внимательно: "...для преобразования указателей...", а не между указателями и интегралами; и "...такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении" как раз исключает ситуацию, которую ты хочешь осуществить, а я соответственно комментирую. Цитата для преобразования указателей лучше использовать двойной static_cast через void* вместо reinterpret_cast, потому как такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении https://habrahabr.ru/post/106294/ Добавлено Цитата Eric-S @ С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>. Упс. А я и запамятовал о таком весёлом хаке. Иногда сам делал. А тут даже не подумал применить. Спасибо за идеию! |
Сообщ.
#6
,
|
|
|
Цитата Qraizer @ С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>. Да, знаю. Но я хотел, чтоб входное значение, сразу возвращалось. Тест в первом сообщении только для наглядности. У меня в реале шяблонная функция, которая принимает указатель произвольного типа и возвращает число. Добавлено Цитата Qraizer @ Читай внимательно: "...для преобразования указателей...", а не между указателями и интегралами; и "...такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении" как раз исключает ситуацию, которую ты хочешь осуществить, а я соответственно комментирую. Понятно. Спасибо. Это я затупил. |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>. А я полагаю, что это всё-таки не совсем так. reinterpret_cast или преобразование типов в стиле С это такой примерно приказ: "Компилятор ! Приказываю считать жёлтое - зелёным ! Твоё мнение меня не интересует." В данном случае Eric-S желает узнать значение указателя. Указатель - это тоже участок памяти некоторого размера. Узнаем его адрес, преобразуем тип адреса в адрес на переменную, равную по длине оригинальному указателю. Разименуем указатель и, таким образом, прочитаем значение указателя. --- Ещё можно использовать пару sprintf/sscanf. |
Сообщ.
#8
,
|
|
|
Цитата ЫукпШ @ В данном случае Eric-S желает узнать значение указателя. Да, именно его. В числовом представлении. И так, чтоб компилятор это в усмерть не заоптимизировал. Но причём максимально легальным способом. |
Сообщ.
#9
,
|
|
|
ЫукпШ, это работает ровно до тех пор, пока репрезентация указателей разных типов одинакова. Никто не гарантирует, что так оно и будет везде и всегда. И даже больше: кое-где это не так.
Философия кастов довольно проста, хотя и не очевидна. Когда программисту требуется некая сущность, ему в подавляющем большинстве случаев пофигу её репрезентация, но ему важны её свойства. Он декларирует как раз свойства этой сущности, назначая ей тип, а не способ её репрезентации в памяти. Когда программисту требуется сменить тип сущности, в подавляющем большинстве случаев ему нужно сменить набор её свойств, а не репрезентацию в памяти. Собственно поэтому считается, что если программа содержит много кастов, она плохо спроектирована, ибо ненормально, что когда свойства сущностей меняются часто. Так вот. В подавляющем большинстве случаев программисту нужно сменить свойства без потери хранимой информации. Это static_cast<>. Зачастую для сохранения хранимого значения при смене типа требуется сменить репрезентацию в памяти. Но программиста это обычно не заботит. Ему важно, что он имел, например, значение 123 со свойствами целого, а теперь ему понадобилось значение со свойствами вещественного, но то же самое, т.е. 123. Но изредка ему нужно ту же, уже имеющуюся, репрезентацию считать как сущность с другими свойствами. Например, когда это значение собирается по кусочкам посредством сериализации/десериализации. Вот тогда reinterpret_cast<>. Т.к. такая сборка по кусочкам крайне зависима от реализации, подобный код непортабелен, и должен быть хорошо различим в исходных текстах. Посему скрывать сие под парой static_cast<>-ов по меньшей мере зарывать грабли под траву. Так что я вообще не понимаю, что за задача у Eric-S. |
Сообщ.
#10
,
|
|
|
Цитата Qraizer @ ЫукпШ, это работает ровно до тех пор, пока репрезентация указателей разных типов одинакова. Никто не гарантирует, что так оно и будет везде и всегда. И даже больше: кое-где это не так. А можно поподробнее? И как такие ситуации узнать? Добавлено Цитата Qraizer @ Вот тогда reinterpret_cast<>. Т.к. такая сборка по кусочкам крайне зависима от реализации, подобный код непортабелен, и должен быть хорошо различим в исходных текстах. Посему скрывать сие под парой static_cast<>-ов по меньшей мере зарывать грабли под траву. Раньше, и довольно долго, у меня был именно reinterpret_cast. Но несколько раз попадались утверждения, что компиляторы, сущности пропущенные через reinterpret_cast, как-то странно размещают. Я так понял, что неоднозначно использовать такие значения. Но возможно, я что-то криво понял. |
Сообщ.
#11
,
|
|
|
Цитата Eric-S @ Одно из двух: либо reinterpret_cast<> использовался не по назначению (как-то была тема, где автор пытался им перекрёстное приведение сделать, за которое вообще-то отвечает dynamic_cast<>, но он пытался static_cast<>-ом и естественно получал ошибку компиляции, а reinterpret_cast<> конечно же молча глотал, но вот в run-time... неудивительно, что эксепшн), либо он неверно использовался, например, к данным с разными требованиями к выравниванию. Но несколько раз попадались утверждения, что компиляторы, сущности пропущенные через reinterpret_cast, как-то странно размещают. Добавлено Цитата Eric-S @ Ну как-как... по документации на исполнительную платформу. Был такой микропроцессор, который имел 4Гб адресное пространство, но только 1Гб физической памяти, при этом один и тот же один гигабайт отображался на все четыре, и номер гигабайта выбирал ширину данных: 1 байт, 2 байта, 4 байта или 8 байт. А можно поподробнее? И как такие ситуации узнать? Добавлено Компилятор естественно это учитывал при всяких там char data[1024]; (int*)data[10], но вот ты поди с интами так просто сделай. |
Сообщ.
#12
,
|
|
|
Цитата Qraizer @ Одно из двух... Возможно и так. Я глубоко не рыл. Как-то даже слышал, что типы int и float могут размещать в разной памяти. В том смысле, что у них может быть одновременно один адрес, но там будут храниться два разных значения. И компилятор обязан это учитывать. Но вспомнить могу лишь древнюю числодробилку Урал-1 т-ща Ромеева. Там вроде как было два барабана, на первый писались целые, а на второй дробные числа. Добавлено Цитата Qraizer @ Ну как-как... по документации на исполнительную платформу. Документация это понятно. Я-то надеялся, что есть какой-то стандартный признак для переключения. Вообщем, я откотил ревизию и вернулся к reinterpret_cast. Ваша правда - нечего мудрить, если работает более простой и понятный вариант. |
Сообщ.
#13
,
|
|
|
Цитата Qraizer @ Какой-то из сигнальников Texas Instruments помнится так устроен. Был такой микропроцессор, который имел 4Гб адресное пространство, но только 1Гб физической памяти |
Сообщ.
#14
,
|
|
|
Я не помню, amk. Я с ним не работал. В КБ, до меня, работали и рассказывали. Я тогда, более 15 лет назад, только-только приобщался к понятию портабельного программирования. Поневоле, ибо приходилось писать под железку с крайне слабыми отладочными средствами, поэтому всё что можно, пытались писать и отлаживать на привычном окружении PC под Win98/XP. Рассказ оказался поучительным.
Добавлено Ещё рассказывали про 32-битный DSP с CHAR_BIT, равным 32. Не менее весёлая архитектура. Зато sizeof чего угодно == 1. |
Сообщ.
#15
,
|
|
|
Цитата Qraizer @ Ну, остальные DSP от TI именно такие. Там только double имеет размер отличный от 1. По работе не так давно пришлось ознакомиться. Ещё рассказывали про 32-битный DSP с CHAR_BIT, равным 32. Не менее весёлая архитектура. Зато sizeof чего угодно == 1. |