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

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

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

13.08.2008 20:20:27
16 ОТВЕТОВ
РЕШЕНИЕ

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

39
10.05.2016 20:32:07

Попробуй это:

#include <stdio.h>
int main()
{
    char s[] = "fffffffe";
    int x;
    sscanf(s, "%x", &x);
    printf("%u\n", x);
}
18
18.03.2014 15:30:08
Это великолепно. Я никогда не видел этот метод раньше.
Cloud Cho 20.12.2017 21:32:37

@Eric

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

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

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

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

2
23.05.2017 12:25:09
В августе 2008 года сайт был совершенно новым и комментарии не были реализованы .
Derek Park 29.10.2010 20:38:47

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

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

1
26.09.2008 19:20:55
Четыре жалобы: 1) Не компилируется. 2) Идентификатор не обрабатывает нижний регистр 3) Он не работает (A => 1). 4) Неверные символы просто игнорируются! Вы проверяли это?
Martin York 26.09.2008 18:35:03
Вы читали это? «Я на самом деле не компилировал это, поэтому я мог сделать несколько довольно больших ошибок». Так что нет, я не проверял это.
Derek Park 26.09.2008 18:46:28
Вот и ты. Я исправил это. Для записи, он уже обрабатывал нижний регистр с помощью оператора "c & = 0xDF". Это было сломано многими другими способами, все же.
Derek Park 26.09.2008 19:00:36
Пятая жалоба: если вы программируете на ANSI C (и не гарантировано наличие набора символов выполнения на основе ASCII), нет гарантии того 'A' + 1 == 'B'или другого ('a' & 0xDF) == ('A' & 0xDF).
Roland Illig 27.06.2010 16:39:02

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

2
14.08.2008 14:29:34

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

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

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

1
23.08.2008 11:32:17

Если у вас нет 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;
}

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

8
7.02.2016 18:27:56
a[i]-'0'и a[i]-'A'+10также будет работать в редком случае, когда ваша система использует EBCDIC (они все еще существуют).
Patrick Schlüter 5.11.2012 22:35:55
'0'а 'A'также сделайте свой код самодокументированным для людей, которые не запоминают таблицу ASCII.
Peter Cordes 10.05.2016 20:41:41

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

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";
-3
18.06.2014 10:05:50
Это C ++ , он спросил о C .
Sapphire_Brick 26.03.2020 22:40:24

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

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

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

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

4
10.05.2016 20:57:05
Я также прочитал вопрос в виде шестнадцатеричной строки -> десятичная строка, но это не соответствует другим ответам. Я отредактировал вопрос в соответствии с принятым ответом и большинством других ответов. Вопрос string-> string неясен, но заставляет задуматься, можно ли это сделать, не проходя через двоичное целое число в качестве промежуточного шага (например, для чисел, слишком больших, чтобы поместиться в a uint64_t). add-with-carry вниз строка десятичных цифр - отстой, но, вероятно, нет.
Peter Cordes 10.05.2016 20:28:48

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

    #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;
}
1
7.02.2016 18:28:22
Рассмотреть вопрос об изменении void main()вint main(void)
user2045557 24.12.2013 06:37:54
десятичное-> шестнадцатеричное проще: вы можете использовать поиск по таблице для преобразования из 4-битного целого в шестнадцатеричное число без гиганта switch. char hextable[] = { '0', '1', ..., 'A', 'B', ..., 'F' }; И вы можете использовать putcharвместо printf! Кроме того, ваш первый переключатель имеет ошибку: "B"есть для 11 и 12, поэтому 16-> "F". / facepalm
Peter Cordes 10.05.2016 20:44:59

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

#include<stdio.h>
void main()
{
    unsigned int i;
    scanf("%x",&i);
    printf("%d",i);
}
3
5.11.2012 22:18:49
dis будет работать в верхнем и нижнем
rishabh kedia 26.11.2011 22:23:06

Редактировать: теперь совместим с компиляторами MSVC, C ++ и не-GNU (см. Конец).

Вопрос был «самый эффективный способ». ОП не указывает платформу, он может компилировать для чипа 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 или C ++, которые не примут необычное шестнадцатеричное объявление.

Замените первое утверждение этой (более длинной, но более соответствующей) версией:

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
};
31
14.02.2017 10:33:02
Правильно ли я считаю, что hextableкод инициализации - это псевдокод (если так стоит упомянуть), или это какой-то эзотерический синтаксис инициализации массива, с которым я не знаком?
John Carter 7.11.2012 01:02:59
Он не компилируется с Android ndk-build.
hB0 8.11.2013 22:53:48
@ hB0 Я отвечу на это невероятно расплывчатое и бессмысленное наблюдение, отвечая натурой: он отлично компилируется на лязге. Есть 22 предупреждения, но это следовало ожидать.
Orwellophile 17.11.2013 14:45:55
Я использовал инструмент ndk-build в android ndk - developer.android.com/tools/sdk/ndk/index.html, и он не компилируется, что дает мне ошибку именно при объявлении массива. Хотя я люблю фрагмент кода, но я не мог его использовать, поэтому пришлось использовать другой хороший метод (но неэффективный). Не могу дать вам точную ошибку компиляции сейчас .. (уже дал вам +1 в прошлый раз)
hB0 19.11.2013 10:12:56
@ hB0 просто закомментируйте вторую строку кода со словом «[0..255]» и молитесь, чтобы вы никогда не передавали неверный ввод
Orwellophile 20.11.2013 12:38:01
#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);
}
1
7.02.2016 18:29:13
Код преобразует шестнадцатеричный код в десятичный ... нет сложного кодирования ... простой, но работает.
Sunday Efeh 4.08.2012 13:56:37
Боже мой, это, наверное, худшая реализация hex до dec, которую я когда-либо видел. powшутки в сторону? Знайте, что это часто реализуется как pow(a,b) = exp( b * log(a) ). Но даже если нет, преобразование целых чисел в удвоение уже является тяжелой операцией, особенно на современных процессорах.
Patrick Schlüter 5.11.2012 22:32:33
Обратите внимание, что Hex_To_Intего входные данные воспринимаются как цепочка битов base-2, хранящаяся в long. Преобразование шестнадцатеричной строки в целое происходит во время компиляции! «Конверсия» - это просто очень дорогая неоперация, которую можно написать лучше return Hex.
Peter Cordes 10.05.2016 20:50:34

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

Будет выводить: введите описание изображения здесь

6
20.08.2016 10:03:15
Я так не думаю, но, возможно, вы забыли привести некоторые аргументы.
radhoo 17.05.2017 18:38:19

В 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;
}
-2
19.07.2017 12:24:02
строка шестнадцатеричных цифр!
Sapphire_Brick 26.03.2020 22:29:53

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

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

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

... подробнее в аналогичной теме здесь: https://stackoverflow.com/a/58253380/5951263

0
6.10.2019 00:44:55