在C中有效地将十六进制字符串转换为整数?

时间:2008-08-13 20:20:28

标签: c performance hex strtol

在C中,将十六进制数字字符串转换为二进制数unsigned intunsigned long的最有效方法是什么?

例如,如果我有0xFFFFFFFE,我希望int的base10值为4294967294

16 个答案:

答案 0 :(得分:39)

您需要strtolstrtoul。另请参阅Unix man page

答案 1 :(得分:31)

编辑:现在与MSVC,C ++和非GNU编译器兼容(参见结束)。

问题是“最有效的方式”。 OP没有指定平台,他可能正在编译基于RISC的ATMEL芯片,其代码具有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),最大大小仅受编译器的限制。

对于不接受花式hextable声明的非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
};

答案 2 :(得分:15)

试试这个:

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

答案 3 :(得分: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位整数,并且非法的十六进制字符没有错误捕获,则它不起作用。

答案 4 :(得分: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

答案 5 :(得分:4)

好像经常发生,你的问题会遇到严重的术语错误/含糊不清。在共同的演讲中,它通常无关紧要,但在这个具体问题的背景下,它至关重要。

你看,没有“十六进制值”和“十进制值”(或“十六进制数”和“十进制数”)这样的东西。 “十六进制”和“十进制”是值的表示的属性。同时,值(或数字)本身没有表示,因此它们不能是“十六进制”或“十进制”。例如,C语法中的0xF15相同数字的两个不同的表示

我猜你的问题,就是说明的方式,表明你需要将一个值的ASCII十六进制表示(即一个字符串)转换为一个值的ASCII十进制表示(另一个字符串)。一种方法是使用整数表示作为中间表示:首先,将ASCII十六进制表示转换为足够大小的整数(使用strto...组中的函数,如strtol),然后转换整数进入ASCII十进制表示(使用sprintf)。

如果那不是你需要做的事情,那么你必须澄清你的问题,因为不可能从你提出问题的方式中弄明白。

答案 6 :(得分:2)

@Eric

  

为什么有效的代码解决方案会被拒绝?当然,它很丑陋,可能不是最快的方式,但是说“strtol”或“sscanf”更有教育意义。如果你自己尝试一下,你将会了解一些事情发生在幕后的事情。

我真的不认为你的解决方案应该被拒绝,但我猜测它为什么会发生,因为它不太实际。投票的想法是,“最佳”答案将浮动到顶部,虽然你的答案可能对引擎盖下发生的事情(或可能发生的方式)更有启发性,但它绝对不是解析十六进制数字的最佳方法在生产系统中。

同样,从教育的角度来看,我认为你的答案没有任何问题,我当然不会(也没有)投票。不要气馁并且因为有些人不喜欢你的答案而停止发帖。它发生了。

我怀疑我的回答会让你觉得自己被拒绝了会更好,但我知道当你问为什么某些事情被投票失败时我会特别不开心。{/ 3}。

答案 7 :(得分:2)

对于较大的Hex字符串,例如我需要使用strtoul

答案 8 :(得分:2)

十六进制到十进制。不要在在线编译器上运行它,因为它不起作用。

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

答案 9 :(得分:1)

@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比现代硬件上的比较更快。

答案 10 :(得分:1)

  

为什么代码解决方案有效   投票失败?当然,这很难看   ...

也许是因为丑陋不是教育,而有效。另外,我怀疑像我一样,大多数人目前没有编辑的权力(并且根据所需的等级判断 - 永远不会)。

使用数组可以提高效率,但这段代码中没有提到。 它也不考虑大小写,因此它不适用于问题中提供的示例。 FFFFFFFE

答案 11 :(得分:1)

尝试将其从十进制转换为十六进制

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

答案 12 :(得分:1)

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

答案 13 :(得分:0)

如前所述,效率基本上取决于要优化的内容。

当优化代码行时,或者只是在没有完整的标准库的环境中工作时,一种快速而肮脏的选择可能是:

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

答案 14 :(得分: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;
}

答案 15 :(得分:-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";