首页 / 知识

关于性能:在C中将十六进制字符串有效转换为整数?

2023-04-12 03:58:00

Convert a hexadecimal string to an integer efficiently in C?

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

例如,如果我有0xFFFFFFFE,我想要一个以base10值为4294967294int


您需要strtolstrtoul。另请参见Unix手册页


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

问题是"最有效的方法"。 OP没有指定平台,他可能正在为基于RISC的ATMEL芯片进行编译,该芯片带有256字节的闪存用于代码。

为了记录,以及对于那些像我这样的人,他们欣赏"最简单的方式"与"最有效的方式"之间的区别,并且喜欢学习...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 ++编译器或将不接受花式十六进制声明的编译器。

用以下版本(更长,但更合规)替换第一条语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
};

试试这个:

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
    char s[] ="fffffffe";
    int x;
    sscanf(s,"%x", &x);
    printf("%u\
"
, x);
}

如果没有stdlib,则必须手动进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
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位整数,则此方法不起作用,并且对于非法的十六进制字符也没有错误捕获。


对于AVR微控制器,我编写了以下功能,包括相关注释以使其易于理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * 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;
}

例:

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

将输出:
enter image description here


就像经常发生的那样,您的问题遇到了严重的术语错误/歧义。通常来说,这并不重要,但是在这个特定问题的背景下,这一点至关重要。

您会发现,没有"十六进制值"和"十进制值"(或"十六进制数"和"十进制数")之类的东西。"十六进制"和"十进制"是值表示的属性。同时,值(或数字)本身没有表示形式,因此它们不能为"十六进制"或"十进制"。例如,C语法中的0xF15是相同数字的两个不同表示形式。

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

如果这不是您需要做的,那么您必须澄清您的问题,因为不可能从提出问题的方式中弄清楚。


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

1
2
3
4
5
6
7
#include<stdio.h>
void main()
{
    unsigned int i;
    scanf("%x",&i);
    printf("%d",i);
}

对于较大的十六进制字符串(如示例中所示),我需要使用strtoul。


埃里克

Why is a code solution that works getting voted down? Sure, it's ugly and might not be the fastest way to do it, but it's more instructive that saying"strtol" or"sscanf". If you try it yourself you will learn something about how things happen under the hood.

我真的不认为您的解决方案应该被否决,但是我对它为什么会发生的猜测是因为它不太实用。投票的想法是,"最佳"答案会浮到顶部,尽管您的答案可能对幕后发生的事情(或可能的发生方式)更具指导意义,但绝对不是解析十六进制数字的最佳方法在生产系统中。

再次,从教育的角度来看,我认为您的答案没有任何问题,我当然不会(也不会)将其否决。不要因为有些人不喜欢您的答案之一而灰心丧志,停止发布。它发生了。

我怀疑我的回答会使您对自己的被否决感到更好,但是当您问为什么某件事被否决而没有人回答时,我知道这尤其不好玩。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    #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
2
3
4
5
6
7
8
// 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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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);
}

Why is a code solution that works
getting voted down? Sure, it's ugly
...

也许是因为它既丑陋又没有教育意义,而且行不通。另外,我怀疑像我一样,大多数人目前没有编辑的能力(并且根据需要的等级来判断-永远不会)。

数组的使用可以提高效率,但是此代码中未提及。
它还不考虑大小写,因此不适用于问题中提供的示例。 FFFFFFFE


埃里克

I was actually hoping to see a C wizard post something really cool, sort of like what I did but less verbose, while still doing it"manually".

好吧,我不是C专家,但这是我想出的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
}

我本来会进行更多的位屏蔽而不是进行比较,但是我严重怀疑位屏蔽比在现代硬件上进行比较要快得多。


在C语言中,您可以通过多种方式将十六进制数转换为十进制数。一种方法是将十六进制数转换为整数。我个人发现这很简单而且很小。

这是在强制转换的帮助下将十六进制数转换为十进制数的示例代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
#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\
"
, Decimal);  //output
    return 0;
}

目前这仅适用于小写字母,但超级容易使两者同时使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
cout <<"\
Enter 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.\
";

    }
    else
    {
        //cout <<"This is a alpabetical value.\
";

        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\
"
;}
    }
    //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.\
"
;


字符串十六进制性能十六进制数字

最新内容

相关内容

热门文章

推荐文章

标签云

猜你喜欢