﻿# V716\. Suspicious type conversion: HRESULT \-\> BOOL \(BOOL \-\> HRESULT\)\.

Анализатор обнаружил в коде ситуацию, при которой явным или неявным образом производится преобразование типа bool или BOOL к HRESULT или наоборот\. В то время, как такая операция вполне допустима с точки зрения языка C\+\+, она не имеет практического смысла\. Тип HRESULT предназначен для хранения статуса, имеет достаточно сложный формат и не имеет ничего общего с типом bool или BOOL\.

Можно привести следующий пример из реального приложения:

```cpp
BOOL WINAPI DXUT_Dynamic_D3D10StateBlockMaskGetSetting(....)
{
    if( DXUT_EnsureD3D10APIs() &&
        s_DynamicD3D10StateBlockMaskGetSetting != NULL )
        ....
    else
        return E_FAIL;
}
```

Опасность заключается в том, что тип HRESULT представляет собой, на самом деле, тип 'long', а тип BOOL – это ни что иное как 'int'\. Эти типы легко преобразуются друг в друга, и компилятор не видит ничего подозрительного в приведённом выше коде\.

Однако с точки зрения программиста эти типы означают совершенно разное\. В то время как BOOL обозначает логическую переменную, тип HRESULT устроен достаточно сложно и должен сигнализировать о том, прошла ли операция успешно, какой результат был возвращён после выполнения операции, в случае ошибки – где произошла ошибка, обстоятельства этой ошибки и так далее\.

О типе HRESULT\. Первый бит слева \(то есть самый старший бит\) хранит успешность операции: в случае, если операция прошла успешно, первый бит устанавливается в ноль, иначе – в единицу\. Дальнейшие четыре бита характеризуют вид ошибки\. Одиннадцать бит далее характеризуют модуль, в котором произошла исключительная ситуация\. Последние, самые младшие шестнадцать бит характеризуют статус выполнения операции: в случае ошибки он может указывать на код ошибки, в случае успешного выполнения – статус успешного выполнения\. Таким образом, неотрицательные значения обычно сигнализируют об успешном выполнении операции\. При этом часто применяется макро константа 'S\_OK', равная 0\.

Более подробное описание HRESULT можно увидеть в [статье](https://msdn.microsoft.com/en-us/library/cc231198.aspx) на сайте MSDN\. А на [этой странице](https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values) список наиболее часто применяемых значений\.

Тип BOOL для индикации значения "ложь" должен быть равен нулю, в противном случае он указывает на значение "истина"\. Иными словами, эти два типа крайне похожи друг на друга в плане типов и их приведение друг к другу не влечёт за собой с точки зрения языка ничего страшного, однако операция приведения лишена смысла\. Ведь по первоначальному замыслу тип HRESULT хранит в себе не только информацию об успехе или неудаче \(и код ошибки в случае неудачи\), но и может сохранять в себе некоторую дополнительную информацию в случае успешного вызова\. Особенно подпортить жизнь может значение S\_FALSE, равное 0x1\. То, что ненулевые значения возвращаются в случае успешного вызова крайне редко, может стать причиной мучительных поисков ошибок, проявляющихся очень иногда и совсем изредка\. Зачастую можно встретить конструкцию вида:

```cpp
HRESULT result = someWinApiFunction(....);
if (!result)
{
  // This is an error!
}
```

Такой код абсолютно ошибочен, поскольку проверка на ошибку сработает, если функция вернёт 0 в случае успеха\. При этом код обработки ошибки не сработает, когда функция просигнализирует о проблеме, вернув отрицательное число\. При этом подобные неявные преобразования между целочисленным и логическим типом могут происходить в более сложных выражениях, где ошибку сложно заметить невооруженным глазом\.

Для контроля возвращаемого значения типа HRESULT настоятельно предлагаем воспользоваться макросами SUCCEEDED и FAILED\.

```cpp
HRESULT someFunction(int x);
....
BOOL failure = FAILED(someFunction(q));
```

В остальных случаях рефакторинг не так уж и прост, как кажется, и требует по крайней мере вдумчивого чтения и анализа кода\.

Ещё раз о главном\. Помните, что:

* FALSE \=\= 0
* TRUE \=\= 1
* S\_OK \=\= 0
* S\_FALSE \=\= 1
* E\_FAIL \=\= 0x80004005
* и так далее\.

Никогда не смешивайте HRESULT и BOOL\. Смешивание этих типов является серьёзной ошибкой в логике работы программы\. Для проверки значений типа HRESULT используйте специальные макросы\.

Для поиска ситуаций, когда в переменную типа HRESULT помещается true или false, существует родственная диагностика [V543](https://pvs-studio.ru/ru/docs/warnings/v543/)\.