усечение указателя после преобразования x64 - PullRequest
1 голос
/ 08 апреля 2019

Я новичок в C ++ и пытаюсь собрать небольшую устаревшую библиотеку классов, которую я всегда использовал как x86 для x64.

Теперь компилятор показывает несколько предупреждений:

            IUnknown* _p;
            // warning C4311: 'type cast': pointer truncation from 'IUnknown *' to 'int'
            // warning C4302: 'type cast': truncation from 'IUnknown *' to 'int'
            virtual int GetHashCode() override
            {
                return (int)_p;
            }

            // 1> warning C4311: 'type cast': pointer truncation from 'void *' to 'long'
            // 1> warning C4302: 'type cast': truncation from 'void *' to 'long'
            void MyMethod(IntPtr hwnd, String^ str)
            {
                CComBSTR bstrValue = (BSTR)Marshal::StringToBSTR(str).ToPointer();
                HRESULT result = SomeClass()->SomeMethod((long)hwnd.ToPointer(), bstrValue);
            }

, где SomeMethod определен как

#ifdef _X86_
typedef long CUSTOMHWND;
#else
typedef LONGLONG CUSTOMHWND;
#endif

        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SomeMethod( 
            /* [in] */ CUSTOMHWND hwndOwner,
            /* [in] */ __RPC__in BSTR pValue) = 0;

Как мне изменить код, чтобы сделать его безопасным для x64?

Ответы [ 2 ]

1 голос
/ 08 апреля 2019

Как правило, на основе [expr.cast] / 4 , приведение в стиле C в

return (int)_p;

закончится выполнением

return reinterpret_cast<int>(_p);

Теперь, строго говоря, я считаю, что поведение в этом случае на самом деле не определено. Согласно [expr.reinterpret.cast] / 4 :

Указатель может быть явно преобразован в любой целочисленный тип, достаточно большой, чтобы содержать все значения его типа.

Обратите внимание, что стандарт определяет здесь только поведение для случая приведения значения указателя к целочисленному типу, достаточно большому, чтобы содержать любое возможное значение этого типа указателя. Мне не известны какие-либо формулировки в стандарте, которые бы определяли поведение в случае приведения значения указателя к целочисленному типу, который слишком мал, что вы и делаете здесь, поскольку int недостаточно велико ( в MSVC) для представления значения указателя на 64-битный объект. На практике любой компилятор, о котором я когда-либо слышал, просто генерирует код, который возвращает младшие 32 бита (при условии, что int имеет ширину 32 бита) адреса, который содержится здесь _p, но вы, скорее всего, не должны полагаться на что.

В общем, я бы просто избегал приведения указателей к целым числам, если бы вы могли. Если вам действительно нужно, убедитесь, что вы используете целочисленные типы, достаточно большие, чтобы содержать значение указателя. std::intptr_t или std::uintptr_t будет моим первым выбором в этом случае.

С учетом всего вышесказанного, имя вашей функции предполагает, что она просто должна возвращать хеш-значение, предположительно для идентификации какого-либо объекта в хеш-таблице. Если это цель, я бы порекомендовал вам просто использовать std::hash, чтобы вычислить для вас такое значение хеша, а не полагаться на приведение указателей к целочисленным значениям самостоятельно:

        virtual std::size_t GetHashCode() override
        {
            return std::hash<IUnknown*>{}(_p);
        }

Пусть std::hash позаботится о получении хэша для адреса для вас. Вы можете рассчитывать на то, что всегда делаете то, что может быть правильным для получения такого хэша, какой бы целевой платформой ни была & hellip;

1 голос
/ 08 апреля 2019

https://docs.microsoft.com/en-us/cpp/build/common-visual-cpp-64-bit-migration-issues?view=vs-2019

  • Используйте DWORD_PTR и LONG_PTR вместо long, int и т. Д. При обращении к указателям (большинство дескрипторов Windows являются указателями)
  • Если приложение не использует параметр компоновщика LARGEADDRESSAWARE (https://docs.microsoft.com/en-us/cpp/build/reference/largeaddressaware-handle-large-addresses?view=vs-2019)), все указатели ограничиваются нижним 4 ГБ, поэтому усечение не повредит. Это сэкономит ваше время на исправление всех предупреждений.

Дополнительные советы по миграции: https://docs.microsoft.com/en-us/windows/desktop/WinProg64/migration-tips

...