Подтвердить что ты не робот

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

В C наиболее эффективный способ преобразования строки шестнадцатеричных цифр в двоичный unsigned int или unsigned long?

Например, если у меня есть 0xFFFFFFFE, я хочу int с базовым значением 4294967294.

4b9b3361

Ответ 2

Изменить: Теперь совместим с компиляторами MSVC, С++ и не GNU (см. конец).

Вопрос был "наиболее эффективным способом". OP не определяет платформу, он может компилировать для чипа ATMEL на основе RISC с 256 байтами флэш-памяти для своего кода.

Для записи и для тех (как я), которые ценят разницу между "самым простым способом" и "самым эффективным способом", и которым нравится учиться...

static const long hextable[] = {
   [0 ... 255] = -1, // bit aligned access into this table is considerably
   ['0'] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // faster for most modern processors,
   ['A'] = 10, 11, 12, 13, 14, 15,       // for the space conscious, reduce to
   ['a'] = 10, 11, 12, 13, 14, 15        // signed char.
};

/** 
 * @brief convert a hexidecimal string to a signed long
 * will not produce or process negative numbers except 
 * to signal error.
 * 
 * @param hex without decoration, case insensitive. 
 * 
 * @return -1 on error, or result (max (sizeof(long)*8)-1 bits)
 */
long hexdec(unsigned const char *hex) {
   long ret = 0; 
   while (*hex && ret >= 0) {
      ret = (ret << 4) | hextable[*hex++];
   }
   return ret; 
}

Он не требует внешних библиотек, и он должен быть ослепительно быстрым. Он обрабатывает прописные, строчные, недопустимые символы, шестнадцатеричный ввод нечетного размера (например: 0xfff), а максимальный размер ограничен только компилятором.

Для компиляторов или компиляторов, не относящихся к GCC или С++, которые не согласятся с фэнтезийной декларацией.

Замените первый оператор этой (более длинной, но более подходящей) версией:

static const long hextable[] = { 
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};

Ответ 3

Попробуйте следующее:

#include <stdio.h>
int main()
{
    char s[] = "fffffffe";
    int x;
    sscanf(s, "%x", &x);
    printf("%u\n", x);
}

Ответ 4

Если у вас нет 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 бита, и нет ошибки захвата для нелегальных шестнадцатеричных символов.

Ответ 5

Для микроконтроллеров 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);

Будет выводить: enter image description here

Ответ 6

Как будто часто случается, ваш вопрос страдает серьезной терминологической ошибкой/двусмысленностью. В обычной речи это обычно не имеет значения, но в контексте этой конкретной проблемы это критически важно.

Вы видите, нет такой вещи, как "шестнадцатеричное значение" и "десятичное значение" (или "шестнадцатеричное число" и "десятичное число" ). "Hex" и "decimal" являются свойствами представлений значений. Между тем, значения (или числа) сами по себе не имеют представления, поэтому они не могут быть "шестнадцатеричными" или "десятичными". Например, 0xF и 15 в синтаксисе Си представляют собой два разных представления одного и того же числа.

Я бы предположил, что ваш вопрос, как сказано, предполагает, что вам нужно преобразовать шестнадцатеричное представление ASCII значения (т.е. строки) в десятичное представление ASCII значения (другая строка). Один из способов сделать это - использовать целочисленное представление как промежуточное: во-первых, преобразовать шестнадцатеричное представление ASCII в целое число достаточного размера (используя функции из группы strto..., например strtol), затем преобразовать целое число в ASCII десятичное представление (используя sprintf).

Если это не то, что вам нужно сделать, тогда вы должны уточнить свой вопрос, поскольку невозможно понять, как сформулирован ваш вопрос.

Ответ 7

@Eric

Почему решение для кода, которое работает, отклоняется? Конечно, это уродливо и, возможно, не самый быстрый способ сделать это, но более поучительно говорить "strtol" или "sscanf". Если вы попробуете сами, вы узнаете что-то о том, как все происходит под капотом.

Я действительно не думаю, что ваше решение должно было быть отклонено, но я думаю, почему это происходит, потому что это менее практично. Идея с голосованием заключается в том, что "лучший" ответ будет всплывать на вершину, и, хотя ваш ответ может быть более поучительным о том, что происходит под капотом (или как это может произойти), это определенно не лучший способ разбора шестнадцатеричных чисел в производственной системе.

Опять же, я не думаю, что с вашим ответом с образовательной точки зрения что-то не так, и я, конечно, не стал (и не стал) голосовать за него. Не разочаровывайтесь и прекратите публикацию только потому, что некоторым людям не понравился один из ваших ответов. Это происходит.

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

Ответ 8

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

Ответ 9

Шестнадцатеричный до десятичного. Не запускайте его в онлайн-компиляторах, потому что это не сработает.

#include<stdio.h>
void main()
{
    unsigned int i;
    scanf("%x",&i);
    printf("%d",i);
}

Ответ 10

@Eric

Я действительно надеялся, что C-мастер опубликует что-то действительно классное, вроде того, что я сделал, но менее подробный, но все еще делаю это "вручную".

Ну, я не 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;
}

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

Ответ 11

Почему применяется кодовое решение проголосовать? Конечно, это уродливо...

Возможно потому, что, будучи уродливым, он не является учебным и не работает. Кроме того, я подозреваю, что, как и я, большинство людей не имеют права редактировать в настоящее время (и, судя по рангам, никогда не будет).

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

Ответ 12

Попробуйте это преобразовать из десятичного в шестнадцатеричный

    #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;
}

Ответ 13

#include "math.h"
#include "stdio.h"
///////////////////////////////////////////////////////////////
//  The bits arg represents the bit say:8,16,32...                                                                                                              
/////////////////////////////////////////////////////////////
volatile long Hex_To_Int(long Hex,char bits)
{
    long Hex_2_Int;
    char byte;
    Hex_2_Int=0;

    for(byte=0;byte<bits;byte++)
    {
        if(Hex&(0x0001<<byte))
            Hex_2_Int+=1*(pow(2,byte));
        else
            Hex_2_Int+=0*(pow(2,byte));
    }

    return Hex_2_Int;
}
///////////////////////////////////////////////////////////////
//                                                                                                                  
/////////////////////////////////////////////////////////////

void main (void)
{
    int Dec;   
    char Hex=0xFA;
    Dec= Hex_To_Int(Hex,8);  //convert an 8-bis hexadecimal value to a number in base 10
    printf("the number is %d",Dec);
}

Ответ 14

В C вы можете преобразовать шестнадцатеричное число в десятичное множество. Один из способов - преобразовать шестнадцатеричное число в целое число. Я лично считаю, что это просто и мало.

Вот пример кода для преобразования шестнадцатеричного числа в десятичное число с помощью кастинга.

#include <stdio.h>

int main(){
    unsigned char Hexadecimal = 0x6D;   //example hex number
    int Decimal = 0;    //decimal number initialized to 0


        Decimal = (int) Hexadecimal;  //conversion

    printf("The decimal number is %d\n", Decimal);  //output
    return 0;
}

Ответ 15

Как написано ранее, эффективность в основном зависит от того, для чего оптимизируется.

Оптимизация для строк кода или просто работа в среде без полностью оборудованной стандартной библиотеки может быть одной быстрой и грязной опцией:

// makes a number from two ascii hexa characters
int ahex2int(char a, char b){

    a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
    b = (b <= '9') ? b - '0' : (b & 0x7) + 9;

    return (a << 4) + b;
}

... больше в аналогичной теме здесь: fooobar.com/questions/108212/...

Ответ 16

В настоящее время он работает только с нижним регистром, но его очень легко заставить работать с обоими.

cout << "\nEnter a hexadecimal number: ";
cin >> hexNumber;
orighex = hexNumber;

strlength = hexNumber.length();

for (i=0;i<strlength;i++)
{
    hexa = hexNumber.substr(i,1);
    if ((hexa>="0") && (hexa<="9"))
    {
        //cout << "This is a numerical value.\n";
    }
    else
    {
        //cout << "This is a alpabetical value.\n";
        if (hexa=="a"){hexa="10";}
        else if (hexa=="b"){hexa="11";}
        else if (hexa=="c"){hexa="12";}
        else if (hexa=="d"){hexa="13";}
        else if (hexa=="e"){hexa="14";}
        else if (hexa=="f"){hexa="15";}
        else{cout << "INVALID ENTRY! ANSWER WONT BE CORRECT\n";}
    }
    //convert from string to integer

    hx = atoi(hexa.c_str());
    finalhex = finalhex + (hx*pow(16.0,strlength-i-1));
}
cout << "The hexadecimal number: " << orighex << " is " << finalhex << " in decimal.\n";