На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> static_cast для получения значения адреса в числовом представлении
    Здравствуйте!

    Несколько раз встречал рекомендацию, что указатель в число, можно приводить через reinterpret_cast, но рекомендуется через static_cast.
    Решил поправить старый код. Но тут вылезли какие-то ошибки.

    ExpandedWrap disabled
            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 );


    Может быть я пропустил какой-то этап? Или это тот самый мифический глюк компилятора?
    Сообщение отредактировано: Eric-S -
      Это ?
      ExpandedWrap disabled
          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));
        Преобразование между целыми и указателями никогда не были стандартизованы. Любые такие касты определяются исключительно реализациями. Именно по этой причине они и осуществляются посредством reinterpret_cast<>, потому как непереносимы. Поэтому ты нигде не мог читать совет по замене их на static_cast<>.
          Цитата Qraizer @
          Поэтому ты нигде не мог читать совет по замене их на static_cast<>.

          Цитата
          для преобразования указателей лучше использовать двойной static_cast через void* вместо reinterpret_cast, потому как такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении

          https://habrahabr.ru/post/106294/

          Добавлено
          А вот в другой статье, действительно, немного иной смысл. Но после неё я и задумался над приведением указателя в число.
          Цитата

          Но не все так плохо: Результат преобразования указателя в целочисленный тип зависит от используемой реализации, а значит, именно она и должна описывать его поведение. Если ваша реализация предполагает получение численного значения линейного адреса объекта, на который ссылается указатель, и вы знаете, что работаете на архитектуре с плоской моделью памяти, то выходом будет сравнивать целые значения вместо указателей. Сравнение целых чисел не имеет таких ограничений, как сравнение указателей.

          https://habrahabr.ru/company/pvs-studio/blog/340458/

          Добавлено
          Цитата ЫукпШ @
          Это ?

          Упс. А я и запамятовал о таком весёлом хаке. Иногда сам делал. А тут даже не подумал применить. Спасибо за идеию!
            Цитата Eric-S @
            Цитата
            для преобразования указателей лучше использовать двойной static_cast через void* вместо reinterpret_cast, потому как такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении

            https://habrahabr.ru/post/106294/
            Читай внимательно: "...для преобразования указателей...", а не между указателями и интегралами; и "...такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении" как раз исключает ситуацию, которую ты хочешь осуществить, а я соответственно комментирую.

            Добавлено
            Цитата Eric-S @
            Упс. А я и запамятовал о таком весёлом хаке. Иногда сам делал. А тут даже не подумал применить. Спасибо за идеию!
            С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>.
            Сообщение отредактировано: Qraizer -
              Цитата Qraizer @
              С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>.

              Да, знаю. Но я хотел, чтоб входное значение, сразу возвращалось. Тест в первом сообщении только для наглядности.
              У меня в реале шяблонная функция, которая принимает указатель произвольного типа и возвращает число.

              Добавлено
              Цитата Qraizer @
              Читай внимательно: "...для преобразования указателей...", а не между указателями и интегралами; и "...такое преобразование позволяет быть уверенным в том, что только pointer-ы участвуют в приведении" как раз исключает ситуацию, которую ты хочешь осуществить, а я соответственно комментирую.

              Понятно. Спасибо. Это я затупил.
                Цитата Qraizer @
                С тем же успехом ты это можешь сделать через union. Этот ровно тот же самый reinterpret_cast<>.

                А я полагаю, что это всё-таки не совсем так.
                reinterpret_cast или преобразование типов в стиле С это такой примерно приказ:
                "Компилятор ! Приказываю считать жёлтое - зелёным ! Твоё мнение меня не интересует."
                В данном случае Eric-S желает узнать значение указателя.
                Указатель - это тоже участок памяти некоторого размера. Узнаем его адрес, преобразуем
                тип адреса в адрес на переменную, равную по длине оригинальному указателю.
                Разименуем указатель и, таким образом, прочитаем значение указателя.
                ---
                Ещё можно использовать пару sprintf/sscanf.
                Сообщение отредактировано: ЫукпШ -
                  Цитата ЫукпШ @
                  В данном случае Eric-S желает узнать значение указателя.

                  Да, именно его. В числовом представлении. И так, чтоб компилятор это в усмерть не заоптимизировал. Но причём максимально легальным способом.
                    ЫукпШ, это работает ровно до тех пор, пока репрезентация указателей разных типов одинакова. Никто не гарантирует, что так оно и будет везде и всегда. И даже больше: кое-где это не так.
                    Философия кастов довольно проста, хотя и не очевидна. Когда программисту требуется некая сущность, ему в подавляющем большинстве случаев пофигу её репрезентация, но ему важны её свойства. Он декларирует как раз свойства этой сущности, назначая ей тип, а не способ её репрезентации в памяти. Когда программисту требуется сменить тип сущности, в подавляющем большинстве случаев ему нужно сменить набор её свойств, а не репрезентацию в памяти. Собственно поэтому считается, что если программа содержит много кастов, она плохо спроектирована, ибо ненормально, что когда свойства сущностей меняются часто.
                    Так вот. В подавляющем большинстве случаев программисту нужно сменить свойства без потери хранимой информации. Это static_cast<>. Зачастую для сохранения хранимого значения при смене типа требуется сменить репрезентацию в памяти. Но программиста это обычно не заботит. Ему важно, что он имел, например, значение 123 со свойствами целого, а теперь ему понадобилось значение со свойствами вещественного, но то же самое, т.е. 123. Но изредка ему нужно ту же, уже имеющуюся, репрезентацию считать как сущность с другими свойствами. Например, когда это значение собирается по кусочкам посредством сериализации/десериализации. Вот тогда reinterpret_cast<>.
                    Т.к. такая сборка по кусочкам крайне зависима от реализации, подобный код непортабелен, и должен быть хорошо различим в исходных текстах. Посему скрывать сие под парой static_cast<>-ов по меньшей мере зарывать грабли под траву.
                    Так что я вообще не понимаю, что за задача у Eric-S.
                      Цитата Qraizer @
                      ЫукпШ, это работает ровно до тех пор, пока репрезентация указателей разных типов одинакова. Никто не гарантирует, что так оно и будет везде и всегда. И даже больше: кое-где это не так.

                      А можно поподробнее? И как такие ситуации узнать?

                      Добавлено
                      Цитата Qraizer @
                      Вот тогда reinterpret_cast<>.
                      Т.к. такая сборка по кусочкам крайне зависима от реализации, подобный код непортабелен, и должен быть хорошо различим в исходных текстах. Посему скрывать сие под парой static_cast<>-ов по меньшей мере зарывать грабли под траву.

                      Раньше, и довольно долго, у меня был именно reinterpret_cast.
                      Но несколько раз попадались утверждения, что компиляторы, сущности пропущенные через reinterpret_cast, как-то странно размещают.
                      Я так понял, что неоднозначно использовать такие значения.
                      Но возможно, я что-то криво понял.
                        Цитата Eric-S @
                        Но несколько раз попадались утверждения, что компиляторы, сущности пропущенные через reinterpret_cast, как-то странно размещают.
                        Одно из двух: либо reinterpret_cast<> использовался не по назначению (как-то была тема, где автор пытался им перекрёстное приведение сделать, за которое вообще-то отвечает dynamic_cast<>, но он пытался static_cast<>-ом и естественно получал ошибку компиляции, а reinterpret_cast<> конечно же молча глотал, но вот в run-time... неудивительно, что эксепшн), либо он неверно использовался, например, к данным с разными требованиями к выравниванию.

                        Добавлено
                        Цитата Eric-S @
                        А можно поподробнее? И как такие ситуации узнать?
                        Ну как-как... по документации на исполнительную платформу. Был такой микропроцессор, который имел 4Гб адресное пространство, но только 1Гб физической памяти, при этом один и тот же один гигабайт отображался на все четыре, и номер гигабайта выбирал ширину данных: 1 байт, 2 байта, 4 байта или 8 байт.

                        Добавлено
                        Компилятор естественно это учитывал при всяких там char data[1024]; (int*)data[10], но вот ты поди с интами так просто сделай.
                          Цитата Qraizer @
                          Одно из двух...

                          Возможно и так. Я глубоко не рыл.
                          Как-то даже слышал, что типы int и float могут размещать в разной памяти. В том смысле, что у них может быть одновременно один адрес, но там будут храниться два разных значения. И компилятор обязан это учитывать.
                          Но вспомнить могу лишь древнюю числодробилку Урал-1 т-ща Ромеева. Там вроде как было два барабана, на первый писались целые, а на второй дробные числа.

                          Добавлено
                          Цитата Qraizer @
                          Ну как-как... по документации на исполнительную платформу.

                          Документация это понятно. Я-то надеялся, что есть какой-то стандартный признак для переключения.

                          Вообщем, я откотил ревизию и вернулся к reinterpret_cast.
                          Ваша правда - нечего мудрить, если работает более простой и понятный вариант.
                            Цитата Qraizer @
                            Был такой микропроцессор, который имел 4Гб адресное пространство, но только 1Гб физической памяти
                            Какой-то из сигнальников Texas Instruments помнится так устроен.
                              Я не помню, amk. Я с ним не работал. В КБ, до меня, работали и рассказывали. Я тогда, более 15 лет назад, только-только приобщался к понятию портабельного программирования. Поневоле, ибо приходилось писать под железку с крайне слабыми отладочными средствами, поэтому всё что можно, пытались писать и отлаживать на привычном окружении PC под Win98/XP. Рассказ оказался поучительным.

                              Добавлено
                              Ещё рассказывали про 32-битный DSP с CHAR_BIT, равным 32. Не менее весёлая архитектура. Зато sizeof чего угодно == 1.
                                Цитата Qraizer @
                                Ещё рассказывали про 32-битный DSP с CHAR_BIT, равным 32. Не менее весёлая архитектура. Зато sizeof чего угодно == 1.
                                Ну, остальные DSP от TI именно такие. Там только double имеет размер отличный от 1. По работе не так давно пришлось ознакомиться.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0432 ]   [ 17 queries used ]   [ Generated: 28.03.24, 11:49 GMT ]