Hex string to value
От: Аноним  
Дата: 28.10.10 13:38
Оценка:
Понадобилась банальнейшая вещь — преобразовать значение из строки...
Имею строку в которой хранится шестнадцатеричное представление HRESULT.
Ну и нужно получить само значение HRESULT.
Естественно, воспользовался RTL'ной ф-цией. А так как HRESULT есть long'ом, то в качестве ф-ции и выбрал strtol.
Была написана следующая обёрточка:
HRESULT toHResult(const TCHAR *sz) {
   return _tcstol(sz, NULL, 16);
}

Я был удивлён, когда она начала возвращать бред.

После проверки, выяснил, что нужно пользоваться ф-цией strtoul:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <conio.h> 
#include <limits.h>
#include <winerror.h>

//typedef long HRESULT;

HRESULT toHResult(const TCHAR *sz) {
   //long lVal = _tcstol(sz, NULL, 16);
   //return lVal;
   unsigned long ulVal = _tcstoul(sz, NULL, 16);
   return ulVal;
}

int _tmain(int argc, _TCHAR* argv[])
{
   TCHAR *sz = _T("0x80070057"); // E_INVALIDARG
   HRESULT hRes = toHResult(sz);

   bool check = (E_INVALIDARG == hRes);

   char sz2[100];
   std::cout << (check ? "success:\r\n" : "fail:\r\n") << hRes << "\r\n" << ltoa(hRes, sz2, 16);

   return _getch();
}


Вопрос знатокам. Почему для получения signed long значения нужно пользоваться ф-цией возвращающей unsigned long?



В первом случае, когда пользуюсь strtol в консоль выводится

fail:
2147483647
7fffffff


А когда strtoul:

success:
-2147024809
80070057

Re: Hex string to value
От: Were  
Дата: 28.10.10 15:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос знатокам. Почему для получения signed long значения нужно пользоваться ф-цией возвращающей unsigned long?

А зачем ты представил signed long в виде unsigned long в строке? Пиши ее как -0x7FF8FFA9 и будет работать _tcstol.
Re: Hex string to value
От: rus blood Россия  
Дата: 28.10.10 16:00
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Почему для получения signed long значения нужно пользоваться ф-цией возвращающей unsigned long?


Наверно потому, что число hex(80070057) вне диапазона допустимых значений типа signed long ...
Имею скафандр — готов путешествовать!
Re[2]: Hex string to value
От: chpunteg  
Дата: 28.10.10 20:37
Оценка:
Здравствуйте, Were, Вы писали:

W>А зачем ты представил signed long в виде unsigned long в строке? Пиши ее как -0x7FF8FFA9 и будет работать _tcstol.

как же, представил... Мне пришла такая строка — без унарного минуса! И я знаю только, что это тип HRESULT, т.е. просто signed long.

а даже если бы я сам представил, то почему HEX'овая строка 0x80070057 это unsigned? Я, например, вижу крайнем бите единицу, т.е. отрицательное значение.

Интересная ситуация выходит.
При конвертации signed в hex строку
   TCHAR sz[9];
   _ltot(E_INVALIDARG, sz, 16);
получу верное значение "80070057" (а не "-0x7FF8FFA9")
а при обратном — hex в signed
   _tcstol(_T("80070057"), NULL, 16);
получаю неверное LONG_MAX (0x7fffffff)

не логично как-то...
Re[3]: Hex string to value
От: Were  
Дата: 28.10.10 20:56
Оценка:
Здравствуйте, chpunteg, Вы писали:

C>Здравствуйте, Were, Вы писали:


W>>А зачем ты представил signed long в виде unsigned long в строке? Пиши ее как -0x7FF8FFA9 и будет работать _tcstol.

C>как же, представил... Мне пришла такая строка — без унарного минуса! И я знаю только, что это тип HRESULT, т.е. просто signed long.

C>а даже если бы я сам представил, то почему HEX'овая строка 0x80070057 это unsigned? Я, например, вижу крайнем бите единицу, т.е. отрицательное значение.

А функция считает, что это положительное значение, которое не влезает в signed long. Формат входной строки описан в документации к функции кстати, и знак минуса там нужно указывать явно.

C>не логично как-то...

А кто сказал, что функция _ltot обратная для _tcstol? В документации к _ltot сказано, что знак минус ставится только для десятичной базы, а в _tcstol он должен быть указан явно для всех.
В общем используй _tcstoul и преобразуй unsigned в signed.
Re[4]: Hex string to value
От: chpunteg  
Дата: 28.10.10 22:01
Оценка:
Здравствуйте, Were, Вы писали:

W>А функция считает, что это положительное значение, которое не влезает в signed long. Формат входной строки описан в документации к функции кстати, и знак минуса там нужно указывать явно.

W> кто сказал, что функция _ltot обратная для _tcstol? В документации к _ltot сказано, что знак минус ставится только для десятичной базы, а в _tcstol он должен быть указан явно для всех.
да, уже увидел... спасибо.

W>В общем используй _tcstoul и преобразуй unsigned в signed.

в первом посте так сделал...

ЗЫЖ
Нет, я понимаю почему она так конвертит. Сразу понял.
Но до сих пор был уверен, что RTL'ные ф-ции конвертации взаимообратны:
atoi <-> itoa
_ltot <-> _tcstol
_ultot <-> _tcstoul
_i64tot <-> _tcstoi64
...
а оказалось — не всегда

Было удивлен, получив на вызов checkLongStrLong(E_INVALIDARG) значение false
bool checkLongStrLong(long val) {
   TCHAR sz[9];
   return _tcstol(_ltot(val, sz, 16), NULL, 16) == val; // convert signed -> string -> signed
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.