2008-08-13 9 views
16

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

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

ответ

13

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

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

Это блестящий. Я никогда не видел этот метод раньше. – 2017-12-20 21:32:37

1

@Eric

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

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

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

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

+2

-1 Есть причина, по которой у нас есть комментарии ... – alternative 2010-10-29 17:05:13

+6

В августе 2008 года сайт был совершенно новым, и * комментарии не были реализованы *. – 2010-10-29 20:38:47

0

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

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

+0

Четыре жалобы: 1) Он не компилируется. 2) Id не обрабатывает строчный регистр 3) Он не работает (A => 1). 4) Недопустимые символы просто игнорируются !. Вы проверили это? – 2008-09-26 18:35:03

+0

Вы прочитали? «Я на самом деле не собирал это, поэтому я мог бы совершить довольно большие ошибки». Нет, я не проверял. – 2008-09-26 18:46:28

+0

Там вы идете. Я закрепил его. Для записи он уже обрабатывал строчный регистр с помощью инструкции «c & = 0xDF». Тем не менее, он был разбит несколькими другими способами. – 2008-09-26 19:00:36

1

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

0

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

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

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

6

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

+2

`a [i] - '0'` и` a [i] -' A '+ 10` также будут работать в редком случае, когда ваша система использует EBCDIC (они все еще существуют). – 2012-11-05 22:35:55

+1

`` 0`` и `` A`` также делают ваш код самодокументированным, для людей, которые не запоминают таблицу ASCII. – 2016-05-10 20:41:41

-3

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

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

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

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

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

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

+0

Я также прочитал вопрос как шестую строку -> десятичную строку, но это не соответствует другим ответам. Я отредактировал вопрос в соответствии с принятым ответом и большинством других ответов. Строковый вопрос неясен, но заставляет меня задаться вопросом, можно ли это сделать, не проходя через двоичное целое в качестве промежуточного шага (например, для слишком больших чисел, чтобы вписаться в `uint64_t`). add-with-carry вниз строка десятичных цифр засасывает много, хотя, возможно, нет. – 2016-05-10 20:28:48

0

Попробуйте конвертировать из десятичной системы счисления в Hex

#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

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

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

Edit: Теперь совместим с MSVC, C++ и не-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 или C++, которые не согласятся с объявлением hxtable.

Заменить первое заявление с этим (больше, но более соответствующим) версией:

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

Для 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

0

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