Pergunta

Em C, qual é a maneira mais eficiente de converter uma sequência de dígitos hexadecimais em binário? unsigned int ou unsigned long?

Por exemplo, se eu tiver 0xFFFFFFFE, eu quero um int com o valor base10 4294967294.

Foi útil?

Solução

Você quer strtol ou strtoul.Veja também o Página de manual do Unix

Outras dicas

Editar: Agora compatível com compiladores MSVC, C++ e não-GNU (veja final).

A questão era "maneira mais eficiente". O OP não especifica a plataforma, ele pode estar compilando um chip atmel baseado em RISC com 256 bytes de armazenamento flash para seu código.

Para que conste, e para aqueles (como eu), que apreciam a diferença entre "a maneira mais fácil" e a "forma mais eficiente", e que gostam de aprender...

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

Não requer bibliotecas externas e deve ser extremamente rápido.Ele lida com caracteres maiúsculos, minúsculos, inválidos, entrada hexadecimal de tamanho ímpar (por exemplo:0xfff), e o tamanho máximo é limitado apenas pelo compilador.

Para compiladores não-GCC ou C++ ou compiladores que não aceitarão a declaração hextabela sofisticada.

Substitua a primeira instrução por esta versão (mais longa, mas mais conforme):

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

Experimente isto:

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

Se você não tiver o stdlib, terá que fazer isso manualmente.

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

Observação:Este código assume AF maiúsculo.Não funciona se len estiver além do número inteiro mais longo de 32 ou 64 bits e não houver captura de erros para caracteres hexadecimais ilegais.

Para microcontroladores AVR escrevi a seguinte função, incluindo comentários relevantes para facilitar o entendimento:

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

Exemplo:

char *z ="82ABC1EF";
uint32_t x = hex2int(z);
printf("Number is [%X]\n", x);

Produzirá:enter image description here

Como acontece com frequência, sua pergunta sofre de um sério erro/ambiguidade terminológica.Na linguagem comum isso geralmente não importa, mas no contexto deste problema específico é extremamente importante.

Veja, não existem "valor hexadecimal" e "valor decimal" (ou "número hexadecimal" e "número decimal")."Hex" e "decimal" são propriedades de representações de valores.Enquanto isso, os valores (ou números) por si só não têm representação, portanto não podem ser "hexadecimais" ou "decimais".Por exemplo, 0xF e 15 na sintaxe C são dois diferentes representações de o mesmo número.

Eu acho que sua pergunta, da forma como é apresentada, sugere que você precisa converter a representação hexadecimal ASCII de um valor (ou seja,uma string) em uma representação decimal ASCII de um valor (outra string).Uma maneira de fazer isso é usar uma representação inteira como intermediária:primeiro, converta a representação hexadecimal ASCII em um número inteiro de tamanho suficiente (usando funções de strto... grupo, como strtol) e, em seguida, converta o número inteiro na representação decimal ASCII (usando sprintf).

Se não é isso que você precisa fazer, então você terá que esclarecer sua pergunta, pois é impossível entendê-la pela forma como sua pergunta é formulada.

@Érico

Por que uma solução de código que funciona está sendo rejeitada?Claro, é feio e pode não ser a maneira mais rápida de fazer isso, mas é mais instrutivo do que dizer "strtol" ou "sscanf".Se você tentar você mesmo, aprenderá algo sobre como as coisas acontecem nos bastidores.

Eu realmente não acho que sua solução deveria ter sido rejeitada, mas meu palpite sobre por que isso está acontecendo é porque é menos prático.A ideia da votação é que a "melhor" resposta flutue para o topo e, embora sua resposta possa ser mais instrutiva sobre o que acontece nos bastidores (ou como isso pode acontecer), definitivamente não é a melhor maneira de analisar números hexadecimais em um sistema de produção.

Novamente, não acho que haja nada de errado com sua resposta do ponto de vista educacional, e certamente não votaria (e não votei) contra ela.Não desanime e pare de postar só porque algumas pessoas não gostaram de uma de suas respostas.Acontece.

Duvido que minha resposta faça você se sentir melhor por ter sido rejeitada, mas sei que não é especialmente divertido quando você pergunta por que algo está sendo rejeitado e ninguém responde.

Para strings hexadecimais maiores, como no exemplo que precisei usar strtoul.

Hexadecimal para decimal.Não execute em compiladores online, porque não funcionará.

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

Por que uma solução de código está sendo elevada?Claro, é feio ...

Talvez porque além de feio não seja educativo e não trabalhar.Além disso, suspeito que, assim como eu, a maioria das pessoas não tem o poder de editar no momento (e, a julgar pela classificação necessária, nunca terá).

O uso de um array pode ser bom para eficiência, mas isso não é mencionado neste código.Também não leva em consideração letras maiúsculas e minúsculas, por isso não funciona no exemplo fornecido na pergunta.FFFFFFFE

@Érico

Na verdade, eu esperava ver um assistente C postar algo muito legal, mais ou menos parecido com o que eu fiz, mas menos detalhado, enquanto ainda fazia isso "manualmente".

Bem, não sou um guru de C, mas aqui está o que descobri:

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

Originalmente, eu tinha mais máscaras de bits em vez de comparações, mas duvido seriamente que a máscara de bits seja mais rápida do que a comparação em hardware moderno.

Tente isto para converter de decimal para hexadecimal

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

Em C você pode converter um número hexadecimal em decimal de várias maneiras.Uma maneira é converter o número hexadecimal em um número inteiro.Eu pessoalmente achei isso simples e pequeno.

Aqui está um exemplo de código para converter um número hexadecimal em um número decimal com a ajuda de conversão.

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

Atualmente, isso funciona apenas com letras minúsculas, mas é muito fácil fazê-lo funcionar com ambos.

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";
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top