#c #winapi #casting #visual-studio-2019 #compiler-warnings
Вопрос:
Документы для ShellExecute
штата (курсив мой):
Возвращаемое значение
Тип: ПОМЕХА
Если функция выполняется успешно, она возвращает значение, превышающее 32. Если функция завершается сбоем, она возвращает значение ошибки, указывающее на причину сбоя. Возвращаемое значение используется как ПРЕПЯТСТВИЕ для обратной совместимости с 16-разрядными приложениями Windows. Однако это не является истинным ПРЕПЯТСТВИЕМ. Его можно привести только к значению int и сравнить либо с 32, либо со следующими кодами ошибок ниже.
Однако повиноваться им так:
if ((int)ShellExecuteW(...) <= 32) ...
Выдает предупреждения при компиляции с MSVC 2019 (как 32 -, так и 64-разрядной):
warning C4311: 'type cast': pointer truncation from 'HINSTANCE' to 'int'
warning C4302: 'type cast': truncation from 'HINSTANCE' to 'int'
Использование reinterpret_cast<int>
дает аналогичные результаты.
Я могу подавить предупреждения для этой строки:
#pragma warning(suppress: 4311 4302)
if ((int)ShellExecuteW(...) <= 32) ...
Но мне вообще не нравится это делать, если только нет других вариантов. Поэтому мой вопрос таков: есть ли другие варианты? Есть ли какой-нибудь синтаксис C , который позволяет мне соблюдать документацию API без создания предупреждений?
Комментарии:
1. @JasonC Есть и другие причины для использования
ShellExecuteEx()
, помимо простой возможности собирать информацию о порожденном процессе. Обработка ошибок, совместимая с другими API, является еще одной причиной.2. я не знаю о «рекомендации API», но приведение
(DWORD)(DWORD_PTR)
правильное. в документации говорится, что возвращаемое значение может быть приведено к *int * — такDWORD
что на самом деле то же самое. только без подписи3. На самом деле не имеет значения , используете ли вы
int
илиDWORD
, на самом деле значения,ShellExecute()
возвращаемые при сбое, будут находиться в диапазоне0..32
, который оба типа представляют с одинаковыми битами.4. формально конечно
((int)(ULONG_PTR)ShellExecuteW <= 32)
и(((UINT)(ULONG_PTR)ShellExecuteW <= 32)
— разные вещи. например, если-1
будет возвращено — первый тест будет истинным, а второй-ложным. если вы хотите быть очень строгими — вы можете использовать(INT)(INT_PTR)ShellExecuteW
приведение илиPtrToInt
макрос. но на самом деле более простое использованиеShellExecuteExW
— это моя рекомендация5. @JasonC —
PtrToInt
объявлено в basetsd.h и указано в документации, в которой говорится о преобразовании в int по смыслу — ошибки здесь не подписаны. быстрее плохая документация. правильнее было бы сказать о приведении к uint
Ответ №1:
HINSTANCE
является типом указателя. Компилятор предупреждает вас , что размер указателя больше, чем размер an int
, поэтому биты будут усечены во время приведения HINSTANCE
к int
. Это происходит, когда вы компилируете для 64-битной версии, где указатель равен 8 байтам и int
равен 4 байтам.
В данной конкретной ситуации это усечение нормально, так как значения никогда не будут превышать того, что int
может содержать an. Но, если вы действительно хотите избежать предупреждений, просто используйте intptr_t
или INT_PTR
или любой другой подобный целочисленный тип размером с указатель, например:
if (reinterpret_cast<intptr_t>(ShellExecuteW(...)) <= 32) {
...
}
В противном случае просто не используйте ShellExecute()
вообще, используйте ShellExecuteEx()
вместо этого. Он возвращает значение a BOOL
для успеха/сбоя и использует GetLastError()
для сообщения о стандартных кодах ошибок Win32 при сбое (большинство кодов ошибок, возвращаемых, ShellExecute()
не являются стандартными кодами ошибок Win32), например:
SHELLEXECUTEINFOW info = {...};
if (!ShellExecuteExW(amp;info)) {
DWORD error = GetLastError();
...
}
Комментарии:
1. Должен ли я просто согласиться с тем, что
intptr_t
/INT_PTR
отличаются от задокументированной APIint
рекомендации, и тогда двигаться дальше по своей жизни?2. @JasonC да.
ShellExecute()
Документация была написана в то время, когда 64-битного программирования еще даже не существовало. Если вы действительно хотите быть внимательным, просто бросьтеintptr_t
наint
потом.3. @JasonC — если значение может быть приведено к int — оно также может быть приведено к INT_PTR . если вы понимаете, как эта внутренняя работа
4. Все в порядке. Я убежден. Я пойду по
(int)(intptr_t)
пути стиля здесь.