将十六进制字符串(char [])转换为int?


Answers:


207

你试过了strtol()吗?

strtol-将字符串转换为长整数

例:

const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);

如果数字的字符串表示形式以0x前缀开头,则必须以0为基数:

const char *hexstring = "0xabcdef0";
int number = (int)strtol(hexstring, NULL, 0);

(也可以指定一个明确的基数,例如16,但我不建议引入冗余。)


4
如果十六进制字符串始终由"0x"问题中给定的a引入,则应使用0代替16
詹斯·古斯特

16
@KelvinHu不信任cplusplus.com,这很糟糕。如果有,请访问cppreference.com

1
@KelvinHu该站点上有许多技术上不正确或措辞松散的信息,如果您看到SO的C ++程序员,他们都会因为这个原因而劝阻他们。

1
@ H2CO3好吧,我知道,我是C ++的新手,所以我用Google搜索了此文件,它将cplusplus.com放在了最前面。非常感谢您的信息。
Kelvin Hu

3
附带说明strtol一下long,当您处理非常大的十六进制时,该类型非常有用。使用strtoll类型long long为更大的不吉利的东西。
史蒂文·卢

20

或者,如果您想拥有自己的实现,我以以下快速函数为例:

/**
 * 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
        uint8_t 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
对于资源有限的平台(例如微控制器)非常有用。
Mubin Icyer

19

这样的事情可能会有用:

char str[] = "0x1800785";
int num;

sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num); 

阅读人sscanf


1
这会导致行为不确定,%x必须接收的地址unsigned int。而且即使您解决了该问题,如果字符串表示的数字大于该数字,UINT_MAX那么它又是未定义的行为
MM

10

假设您的意思是字符串,strtol怎么样?


我最初链接到strtod(-> double)而不是strtol。我猜有人在编辑时看到了它。
詹姆斯·麦克劳克林

好吧,这没什么大不了的...如果编译器提供给,编译器会自动广播返回值int。+1,顺便说一句。

我不认为double可以存储32位整数可以存储的所有可能值(实际上,有人知道这是真的吗?我不是100%的浮点数表示形式。)
James McLaughlin

4
@JamesMcLaughlin可以。64位IEEE double具有约2 ^ 53的积分精度。

详细信息,“ 64位IEEE double具有约2 ^ 53的积分精度。” 和一个标志位。因此它可以处理int54_tuint53_t
chux-恢复莫妮卡2015年

5

使用strtol,如果您有可用的libc像顶端回答提示。但是,如果您喜欢自定义的东西,或者在没有libc的微控制器上运行,则可能需要一个稍微优化的版本,而不需要复杂的分支。

#include <inttypes.h>


/**
 * xtou64
 * Take a hex string and convert it to a 64bit number (max 16 hex digits).
 * The string must only contain digits and valid hex characters.
 */
uint64_t xtou64(const char *str)
{
    uint64_t res = 0;
    char c;

    while ((c = *str++)) {
        char v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8);
        res = (res << 4) | (uint64_t) v;
    }

    return res;
} 

移位魔术可以归结为:仅使用最后4位,但是如果它不是一个数字,则还要加9。


如果有机会,您能否详细说明一下“ v =”行的工作方式?我设法实现了自己的功能,如下所示:unsigned long long int hextou64(char *str) { unsigned long long int n = 0; char c, v; for (unsigned char i = 0; i < 16; i++) { c = *(str + i); v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8); n = (n << 4) | (unsigned long long int)v; } return n; }
iamoumuamua

让我看看是否可以将它们放在一起^^我猜这非常棘手。。前提:“ 0”-“ 9”都以“ 0011 ???”开头?以二进制形式。'A'-'F'均以'0100 ???? 以二进制形式。我们可以使用此信息来避免分支。(c&0xF)→仅最后四位包含该值。这已经是'0'-'9'的正确值。对于'A'-'F',我们必须添加一个十进制9以获取正确的值。(例如,十六进制C以0011结尾。是3。但是我们要12。因此我们必须加9。 (c >> 6) | ((c >> 3) & 0x8)→如果是字母,则结果为9,如果是小数,则结果为
0。

3

尝试下面的代码块,它为我工作。

char *p = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);

printf("value x: %x - %d", intVal, intVal);

输出为:

value x: 820 - 2080

3

因此,经过一段时间的搜索后发现strtol相当慢,我已经编写了自己的函数。它仅对字母大写有效,但是添加小写功能不是问题。

int hexToInt(PCHAR _hex, int offset = 0, int size = 6)
{
    int _result = 0;
    DWORD _resultPtr = reinterpret_cast<DWORD>(&_result);
    for(int i=0;i<size;i+=2)
    {
        int _multiplierFirstValue = 0, _addonSecondValue = 0;

        char _firstChar = _hex[offset + i];
        if(_firstChar >= 0x30 && _firstChar <= 0x39)
            _multiplierFirstValue = _firstChar - 0x30;
        else if(_firstChar >= 0x41 && _firstChar <= 0x46)
            _multiplierFirstValue = 10 + (_firstChar - 0x41);

        char _secndChar = _hex[offset + i + 1];
        if(_secndChar >= 0x30 && _secndChar <= 0x39)
            _addonSecondValue = _secndChar - 0x30;
        else if(_secndChar >= 0x41 && _secndChar <= 0x46)
            _addonSecondValue = 10 + (_secndChar - 0x41);

        *(BYTE *)(_resultPtr + (size / 2) - (i / 2) - 1) = (BYTE)(_multiplierFirstValue * 16 + _addonSecondValue);
    }
    return _result;
}

用法:

char *someHex = "#CCFF00FF";
int hexDevalue = hexToInt(someHex, 1, 8);

1是因为我们要转换的十六进制从偏移量1开始,而8是因为它是十六进制长度。

速度测试(1.000.000个电话):

strtol ~ 0.4400s
hexToInt ~ 0.1100s

2

一种快速而肮脏的解决方案:

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

您必须确保输入正确,不包含验证(可能会说是C)。好东西它非常紧凑,可以同时使用“ A”到“ F”以及“ a”到“ f”。

该方法依赖于ASCII表中字母字符的位置,让我们看一下Wikipedia(https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png)。长话短说,数字在字符下方,因此通过将代码减去零即可轻松转换数字字符(0至9)。读取字母字符(A至F)的方法是将除后三位以外的其他零(有效地使其使用大写或小写),然后减去一个(由于位屏蔽后,字母从位置1开始),然后加上十(因为A到F代表十六进制代码的第十到十五个值)。最后,我们需要将构成编码数字的上下半字节的两个数字结合起来。

在这里,我们采用相同的方法(略有不同):

#include <stdio.h>

// takes a null-terminated string of hexa characters and tries to 
// convert it to numbers
long ahex2num(unsigned char *in){

    unsigned char *pin = in; // lets use pointer to loop through the string
    long out = 0;  // here we accumulate the result

    while(*pin != 0){
        out <<= 4; // we have one more input character, so 
                   // we shift the accumulated interim-result one order up
        out +=  (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9; // add the new nibble
        pin++; // go ahead
    }

    return out;
}

// main function will test our conversion fn
int main(void) {

    unsigned char str[] = "1800785";  // no 0x prefix, please
    long num;

    num = ahex2num(str);  // call the function

    printf("Input: %s\n",str);  // print input string
    printf("Output: %x\n",num);  // print the converted number back as hexa
    printf("Check: %ld = %ld \n",num,0x1800785);  // check the numeric values matches

    return 0;
}

1
发布答案后,我发现我错过了@LimeRed的帖子,这很可爱
Simon

1

这是一个将包含十六进制的char数组直接转换为不需要额外库的整数的函数:

int hexadecimal2int(char *hdec) {
    int finalval = 0;
    while (*hdec) {
        
        int onebyte = *hdec++; 
        
        if (onebyte >= '0' && onebyte <= '9'){onebyte = onebyte - '0';}
        else if (onebyte >= 'a' && onebyte <='f') {onebyte = onebyte - 'a' + 10;}
        else if (onebyte >= 'A' && onebyte <='F') {onebyte = onebyte - 'A' + 10;}  
        
        finalval = (finalval << 4) | (onebyte & 0xF);
    }
    finalval = finalval - 524288;
    return finalval;
}

0

我做了一个库,使十六进制/十进制转换不使用stdio.h。使用非常简单:

unsigned hexdec (const char *hex, const int s_hex);

在第一次转换之前,使用以下命令初始化用于转换的数组:

void init_hexdec ();

这里是github上的链接:https : //github.com/kevmuret/libhex/


0

我做过类似的事情,认为这可能对您有所帮助

int main(){ int co[8],i;char ch[8];printf("please enter the string:");scanf("%s",ch);for(i=0;i<=7;i++){if((ch[i]>='A')&&(ch[i]<='F')){co[i]=(unsigned int)ch[i]-'A'+10;}else if((ch[i]>='0')&&(ch[i]<='9')){co[i]=(unsigned int)ch[i]-'0'+0;}}

在这里,我只取了8个字符的字符串。如果您希望为'a'到'f'添加类似的逻辑以给出等效的十六进制值,我还没有这样做,因为我不需要它。


-1

使用xtoi(stdlib.h)。该字符串的前两个索引为“ 0x”,因此通过发送xtoi&val [2]来修剪val [0]和val [1]。

xtoi( &val[2] );


xtoi不是标准功能
MM

-5

我知道这确实很老,但我认为解决方案看起来太复杂了。在VB中尝试以下操作:

Public Function HexToInt(sHEX as String) as long
Dim iLen as Integer
Dim i as Integer 
Dim SumValue as Long 
Dim iVal as long
Dim AscVal as long

    iLen = Len(sHEX)
    For i = 1 to Len(sHEX)
      AscVal = Asc(UCase(Mid$(sHEX, i,  1)))
      If AscVal >= 48 And AscVal  <= 57 Then
        iVal  = AscVal - 48
      ElseIf AscVal >= 65 And AscVal <= 70 Then
        iVal = AscVal - 55
      End If 
      SumValue = SumValue + iVal * 16 ^ (iLen- i)
    Next i 
    HexToInt  = SumValue
End Function 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.