将十六进制数字字符串转换为位字符串

时间:2015-07-27 06:48:32

标签: c

我正在尝试创建一个ASN.1 BITSTRING

首先,我有一个像"abcd..."这样的长十六进制字符串,我认为它必须在输出中成为{ 0xab, 0xcd ... },但不知道从哪里开始(sscanf()一次只有2个字符? )。在使用char[]错误地转换为1010101111001101后实现了这一点,但这不是二进制输出,它是以字符串形式显示的二进制数字。

How to convert a hexadecimal string to a binary string in C似乎对我不起作用(res数组空出来)。

EDIT1

基于评论(在查看优秀答案之前),我想出了以下内容。在给出答案之前会让其他人发表评论。

char input[] = "abcd";
char output[MAX_LENGTH];

char c[3];
int p = 0;
int b = 0;
while (input[p])
{
    strncpy(c, input + p, 2);
    c[2] = '\0';
    p += 2;
    output[ b++ ] = strtol(c, NULL, 16);
}

3 个答案:

答案 0 :(得分:1)

如果你需要转换" ab"到0xab你可以简单地写

bool StrToHexDigit (char digit, char *converted)
{
   bool retVal = true;

   if (digit > '9')
   {
       if ((digit >= 'a') && (digit < 'g'))
// OR  if ((digit > 0x60) && (digit < 'g'))
       {
          *converted = digit - 'a';
       }

       if ((digit >= 'A') && (digit < 'G'))
// OR  if ((digit > 0x40) && (digit < 'G'))
       {
          *converted = digit - 'A';
       }

       *converted += 10;
   }
   else if (digit > '0')
   {
      *converted = digit - '0';
   }
   else
   {
      retVal = false;
   }

   return retVal;
}

bool StrToHex8Bit ( char hi, char low, uint8_t *converted)
{
   bool retVal=StrToHexDigit(hi, &hi)

   if ( retVal == true)
   {
      retVal=StrToHexDigit(low, &low)

      *converted = (hi<<4) | low;
   }

   return retVal;
}

您可以将StrToHexDigit更快地更改,例如:

   if (digit > '9')
   {
       if ((digit > 0x60) && (digit < 'g'))
       {
          *converted = digit - 0x57;
       }

       if ((digit > 0x40) && (digit < 'G'))
       {
          *converted = digit - 0x37;
       }
   }

另一种更快的方法,如果你确定你的字符串的数字(以避免检查数字是否可加入),就是使用查找表:

char lookup[255];

void init_lookup ( void )
{
   lookup['0'] = 0;
   lookup['1'] = 1;
   lookup['2'] = 2;
   lookup['3'] = 3;
   lookup['4'] = 4;
   lookup['5'] = 5;
   lookup['6'] = 6;
   lookup['7'] = 7;
   lookup['8'] = 8;
   lookup['9'] = 9;

   lookup['A'] = 10;
   lookup['B'] = 11;
   lookup['C'] = 12;
   lookup['D'] = 13;
   lookup['E'] = 14;
   lookup['F'] = 15;

   lookup['a'] = 10;
   lookup['b'] = 11;
   lookup['c'] = 12;
   lookup['d'] = 13;
   lookup['e'] = 14;
   lookup['f'] = 15;
}

uint8_t StrToHex (char hi, char low)
{
   return ((lookup[hi]<<4) | lookup[low]);
}

答案 1 :(得分:1)

假设一些任意长度的C字符串,只包含字符0 - 9A - F(或它们的小写版本),那么这应该是很容易实现:

十六进制中的单个数字是二进制的4位,因此两个数字形成一个字节,因此我们需要length / 2个字节来存储完整的转换结果:

uint8_t * hexstr_to_bin(char const * str) {
  size_t const length = strlen(str);
  uint8_t * result = malloc((length + 1) / 2);
  // ...
  return result;
}

然后,人们可以一次一个地迭代字符,并将其转换为它的二进制表示:

size_t it;
for (it = 0; it < length; ++it) {
 char const c = str[it];
 uint8_t const bin = (c > '9') ? (tolower(c) - 'a' + 10) : (c - '0');
 // ...
}

并将其分配到正确的,可能移位的位置:

if (it % 2 == 0) {
 result[it / 2] = bin << 4;
} else {
 result[it / 2] |= bin;
}

当然,在结果数组中排序值的可能性很多。以上代码为live here.(虽然未经测试)

答案 2 :(得分:0)

仅供参考,一个简单的实现一次处理一个半字节作为管道过滤器:

#include <stdio.h>

static char nibble[5];

int main()
{
    int c, i;

    nibble[4] = 0;

    while ((c = fgetc(stdin)) != EOF)
    {
        if (c == '\n') fputc(c, stdout);
        if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f')
            goto cont;

        if (c >= 'a') c -= ('a' - '9' - 1);
        else if (c >= 'A') c -= ('A' - '9' - 1);
        c -= '0';

        for (i = 0; i < 4; ++i)
        {
            nibble[i] = c & 0x8 ? '1' : '0';
            c <<= 1;
        }

        fputs(nibble, stdout);
cont:;
    }
    return 0;
}

结果:

> echo "800f024a" | ./hex2bin
10000000000011110000001001001010