Шестнадцатеричная строка со знаком для длинной функции int - PullRequest
0 голосов
/ 06 мая 2010

Мне нужна функция для преобразования шестнадцатеричной строки со знаком 32 или 24 бита (в дополнение к двум) в длинное целое. Должен работать как на 32-битных, так и на 64-битных машинах (независимо от размера long int) и работать независимо от того, является ли машина двухкомплементной или нет.

РЕШЕНИЕ:

long int hex2li (char hexStr[], int signedHex)
{
   int bits = strlen (hexStr) * 4;

   char *pEnd;
   long long int result = strtoll (hexStr, &pEnd, 16);

   if (pEnd[0] == '\0')
   {
      if (signedHex)
      {
         if (result >= (1LL << (bits - 1))) result -= (1LL << bits);
      }

      return (long int) result;
   }

   return LONG_MIN;
}

Ответы [ 5 ]

5 голосов
/ 06 мая 2010

Для 24-битной строки:

Когда вы анализируете шестнадцатеричную строку, стандартная функция strtol будет читать ее как значение без знака в диапазоне 0 -> 2^24 - 1.

Диапазон 0 -> 2^23 - 1 является правильным, но диапазон 2^23 -> 2^24 - 1 необходимо сопоставить с -2^23 -> -1, что является простым вычитанием, которое можно выполнить следующим образом.

if (result >= (1L << 23))
    result -= (1L << 24);

Чтобы преобразовать 32-битную строку с использованием той же техники, вы должны использовать промежуточный тип, который может представлять полное 32-битное целое число без знака в типе со знаком для выполнения вычитания. long long int гарантированно будет 64-битным, так что вы можете использовать это.

* 1016 Е.Г. *

long int ParseHexStr(const char *in, int bits)
{
    char* endptr;
    long long int result;

    result = strtoll(in, &endptr, 16);

    /*
    ** TODO - error checking, e.g. check endptr != in
    **  Also check for range errors, signalled by LLONG_MIN
    **  LLONG_MAX and a errno == ERANGE.
    */

    if (result >= (1LL << (bits - 1))
        result -= (1LL << bits);

    return result;
}
1 голос
/ 06 мая 2010

Есть ли причина, по которой вы не можете использовать strtol с radix 16?

1 голос
/ 06 мая 2010

У нас есть макрос SIGN_EXTEND, который выглядит следующим образом:

#define SIGN_EXTEND(X, SignBit, Type) \
    (((Type) ((X) << (8 * sizeof(Type) - (SignBit) - 1))) >> \
     (8 * sizeof(Type) - (SignBit) - 1))

Опирается на оператор >> 1, заполняющий вход, когда установлен знаковый бит. Используйте это как:

SIGN_EXTEND(0x89abcd, 23, int32_t);

Для решения вашей проблемы вы можете использовать:

long int hex2li (char string[])
{
    char *pEnd;
    long int result = SIGN_EXTEND(strtol (string, &pEnd, 16), 23, long int);

    if(pEnd[0] == '\0')
        return result;
    return LONG_MIN;
}
1 голос
/ 06 мая 2010

Это сравнение неверно: if (toupper (string[0]) == 'F')

Вам нужно будет продлить знак для любого значения с набором MSB, поэтому что-то вроде:

if(strchr("89ABCDEF", toupper(string[0])) != NULL)

0 голосов
/ 06 мая 2010
  if (toupper (string[0]) == 'F')
  {
     return (result | 0xFF000000);
  }

это даст номер с правильным знаком.

  if (toupper (string[0]) == 'F')
  {
     return ( ~(result | 0xFF000000) + 1);
  }

это всегда даст положительный результат

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...