Вопросы | c

Эффективно преобразовать шестнадцатеричную строку в целое число в C?

Вопрос

Anonymous | 185942 просмотров | рейтинг: 3

В C, каков наиболее эффективный способ преобразования строки шестнадцатеричных цифр в двоичный unsigned int или unsigned long? Например, если у меня есть 0xFFFFFFFE, я хочу int со значением base10 4294967294.



Ответы

Mark Harrison

+ 37 -
Вы хотите strtol или strtoul. Смотрите также справочную страницу Unix  


Patrick

+ 15 -
Попробуйте это:
 #include <stdio.h>
int main()
{
    char s[] = "fffffffe";
    int x;
    sscanf(s, "%x", &x);
    printf("%u/n", x);
}
 

 


Derek Park

+ 2 -
@Eric
  Почему кодовое решение, которое работает, получает отказ? Конечно, это уродливо и, возможно, не самый быстрый способ сделать это, но более поучительно, чем говорить strtol или sscanf. Если вы попробуете это сами, вы узнаете кое-что о том, как все происходит под капотом.
Я не думаю, что ваше решение должно было быть отклонено, но я думаю, почему оно происходит, потому что оно менее практично. Идея с голосованием состоит в том, что лучший ответ будет всплывать наверх, и, хотя ваш ответ может быть более поучительным о том, что происходит под капотом (или как это может произойти), это определенно не лучший способ для анализа шестнадцатеричных чисел в система производства. Опять же, я не думаю, что что-то не так с вашим ответом с образовательной точки зрения, и я, конечно, не стал бы (и не) отказывался от него. Не расстраивайтесь и перестаньте писать только потому, что некоторым людям не понравился один из ваших ответов. Такое случается. Я сомневаюсь, что мой ответ заставляет вас чувствовать себя лучше из-за того, что за вас проголосовали, но я знаю, что особенно не весело, когда вы спрашиваете, почему за что-то проголосовали, и никто не отвечает.  


itj

+ 1 -
@Eric
  На самом деле я надеялся увидеть, как волшебник С публикует что-то действительно классное, вроде того, что я делал, но менее многословно, хотя все еще делал это вручную.
Ну, я не гуру C, но вот что я придумал:
 unsigned int parseHex(const char * str)
{
    unsigned int val = 0;
    char c;

    while(c = *str++)
    {
        val <<= 4;

        if (c >= '0' && c <= '9')
        {
            val += c & 0x0F;
            continue;
        }

        c &= 0xDF;
        if (c >= 'A' && c <= 'F')
        {
            val += (c & 0x07) + 9;
            continue;
        }

        errno = EINVAL;
        return 0;
    }

    return val;
}
 

Изначально у меня было больше масок, а не сравнений, но я серьезно сомневаюсь, что масонство выполняется быстрее, чем сравнение на современном оборудовании.  


AnT

+ 2 -
Для больших шестнадцатеричных строк, как в примере, мне нужно было использовать strtoul.  


radhoo

+ 1 -
  Почему решение кода работает   быть отвергнутым? Конечно это некрасиво   ...
Возможно, потому что, будучи некрасивым, это не воспитательно и не работает. Кроме того, я подозреваю, что, как и я, большинство людей в настоящее время не имеют прав для редактирования (и, судя по необходимому разряду, никогда не получит). Использование массива может быть полезно для эффективности, но это не упоминается в этом коде. Он также не учитывает прописные и строчные буквы, поэтому он не работает для примера, приведенного в вопросе. FFFFFFFE  


MBANZABUGABO Jean Bapitiste

+ 7 -
Если у вас нет stdlib, вы должны сделать это вручную.
 unsigned long hex2int(char *a, unsigned int len)
{
    int i;
    unsigned long val = 0;

    for(i=0;i<len;i++)
       if(a[i] <= 57)
        val += (a[i]-48)*(1<<(4*(len-1-i)));
       else
        val += (a[i]-55)*(1<<(4*(len-1-i)));

    return val;
}
 

Примечание. Этот код предполагает использование заглавных букв A-F. Это не работает, если len превышает ваше самое длинное целое число 32 или 64 бита, и нет никакого перехвата ошибок для недопустимых шестнадцатеричных символов.


Mark Harrison

+ 37 -
Как часто бывает, ваш вопрос страдает от серьезной терминологической ошибки / двусмысленности. В обычной речи это обычно не имеет значения, но в контексте этой конкретной проблемы это критически важно. Видите ли, нет такой вещи, как шестнадцатеричное значение и десятичное значение (или шестнадцатеричное число и десятичное число). Шестнадцатеричный и десятичный являются свойствами представления значений. Между тем, значения (или числа) сами по себе не имеют представления, поэтому они не могут быть шестнадцатеричными или десятичными. Например, 0xF и 15 в C-синтаксисе - это два разных представления одного и того же числа. Я полагаю, что ваш вопрос, как он сформулирован, предполагает, что вам необходимо преобразовать шестнадцатеричное представление значения ASCII (то есть строку) в десятичное представление значения ASCII (другую строку). Один из способов сделать это - использовать целочисленное представление в качестве промежуточного: сначала преобразовать шестнадцатеричное представление ASCII в целое число достаточного размера (используя функции из группы strto..., например, strtol), затем преобразуйте целое число в десятичное представление ASCII (используя sprintf). Если это не то, что вам нужно сделать, то вы должны уточнить свой вопрос, так как это невозможно выяснить из того, как сформулирован ваш вопрос.  


Patrick

+ 15 -
Попробуйте конвертировать из десятичного в шестнадцатеричное
     #include<stdio.h>
    #include<conio.h>

    int main(void)
    {
      int count=0,digit,n,i=0;
      int hex[5];
      clrscr();
      printf("enter a number   ");
      scanf("%d",&n);

      if(n<10)
      {
          printf("%d",n);
      }

      switch(n)
      {
          case 10:
              printf("A");
            break;
          case 11:
              printf("B");
            break;
          case 12:
              printf("B");
            break;
          case 13:
              printf("C");
            break;
          case 14:
              printf("D");
            break;
          case 15:
              printf("E");
            break;
          case 16:
              printf("F");
            break;
          default:;
       }

       while(n>16)
       {
          digit=n%16;
          hex[i]=digit;
          i++;
          count++;
          n=n/16;
       }

       hex[i]=n;

       for(i=count;i>=0;i--)
       {
          switch(hex[i])
          {
             case 10:
                 printf("A");
               break;
             case 11:
                 printf("B");
               break;
             case 12:
                 printf("C");
               break;
             case  13:
                 printf("D");
               break;
             case 14:
                 printf("E");
               break;
             case 15:
                 printf("F");
               break;
             default:
                 printf("%d",hex[i]);
          }
    }

    getch();

    return 0;
}
 

 


Derek Park

+ 2 -
От шестнадцатеричного до десятичного. Не запускайте его на онлайн-компиляторах, потому что он не будет работать.
 #include<stdio.h>
void main()
{
    unsigned int i;
    scanf("%x",&i);
    printf("%d",i);
}
 

 


itj

+ 1 -
Для микроконтроллеров AVR я написал следующую функцию, включая соответствующие комментарии, чтобы ее было легче понять:
 /**
 * hex2int
 * take a hex string and convert it to a 32bit number (max 8 hex digits)
 */
uint32_t hex2int(char *hex) {
    uint32_t val = 0;
    while (*hex) {
        // get current character then increment
        char byte = *hex++;
        // transform hex character to the 4bit equivalent number, using the ascii table indexes
        if (byte >= '0' && byte <= '9') byte = byte - '0';
        else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
        else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
        // shift 4 to make space for new digit, and add the 4 bits of the new digit
        val = (val << 4) | (byte & 0xF);
    }
    return val;
}
 

Пример:
 char *z ="82ABC1EF";
uint32_t x = hex2int(z);
printf("Number is [%X]/n", x);
 

Будет выводить:


Теги

c | performance | hex | strtol