Избегайте предупреждения MSVC при приведении ShellExecute return (ПОМЕХА) к int

#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 отличаются от задокументированной API int рекомендации, и тогда двигаться дальше по своей жизни?

2. @JasonC да. ShellExecute() Документация была написана в то время, когда 64-битного программирования еще даже не существовало. Если вы действительно хотите быть внимательным, просто бросьте intptr_t на int потом.

3. @JasonC — если значение может быть приведено к int — оно также может быть приведено к INT_PTR . если вы понимаете, как эта внутренняя работа

4. Все в порядке. Я убежден. Я пойду по (int)(intptr_t) пути стиля здесь.