在循环中将十六进制转换为一个字符串

时间:2017-07-30 23:31:48

标签: c c99

我尝试将十六进制值转换为一个字符串,我已经阅读了这个question但我不知道如何以动态方式转换它,就像我的函数得到一个8或9的十六进制序列或更多。如何使用循环优化此代码段,该循环迭代给定的十六进制值并转换每个十六进制值(第一个除外),然后转换为.

/* 
Input: char[] ="2b06010201010300"
Output: char[]="1.3.6.1.2.1.1.3.0"
*/
void test(char * hex_arr)
{
  char string[sizeof(hex_arr)*2+1];
  string[0] = '1';
  string[1] = '.';
  string[2] = '3';
  string[3] = '.';
  sprintf(&string[4], "%x", hex_arr[1]);
  string[5] = '.';
  sprintf(&string[6], "%x", hex_arr[2]);
  // ...
  printf("Output: %s\n", string);
}

输入char[]代表SNMP OBJECT IDENTIFIER

1 个答案:

答案 0 :(得分:1)

请注意,在问题中发布的代码中,使用string[]test()函数中声明了sizeof(hex_arr)。但是hex_arr是指向char的指针,而不是数组,因此这不会为string[]提供正确的大小。此外,此处string是一个自动变量,其生命周期仅限于函数test();如果唯一的目标是打印结果,这很好,但如果结果需要在代码中的其他地方使用,则必须找到另一个解决方案。

解决此问题的一种方法是将输出数组与输入数组一起传递到转换函数中。如果输入格式不可接受,则函数可以返回-1,否则返回0,输出数组可以保存由十六进制数字输入字符串产生的标识符字符串。

输入中的每对数字代表一个十六进制的数字,可以是一个三位十进制数字,每个三位十进制数字(除了最后一个,后跟一个空终止符)有一个添加分隔符后添加;所以每对输入数字最多可转换为四个字符。这意味着将output[]分配为input大小的两倍将足以存储任何结果,包括空终止符的空间。这实际上提供了一些额外的空间,这将是必要的。

id_from_hexstring()函数用于执行转换的方法涉及在循环中使用sscanf()将一对字符作为字符串从输入读入临时缓冲区val_str[]%n转换说明符用于跟踪每次成功转换后到达的位置,在offset中存储成功匹配的数量,并使用此值将指针增加到input[]准备中进行下一次转换。

strtoul()函数用于将存储在val_str[]中的两位十六进制字符串转换为unsigned long值。转换input[]中的第一对字符时,如果转换后的值与IN_PREFIX不匹配,则函数将返回错误代码。否则,OUT_PREFIX将打印到output[]的开头而不是转换后的值。在第一对之后,剩余的转换值将打印到output[]字符串的末尾。

转换循环终止后,在.末尾留下一个尾随的output[]分隔符,最后一个任务是在返回0之前将其删除以表示成功。通过将input[]数组的大小(而不是字符串长度)加倍来确定output[]数组的大小,可以保证output[]可以容纳额外的.分隔符。

此代码可以执行更多操作来验证输入。就像现在一样,id_from_hexstring()函数希望输入由有效的十六进制字符组成。这是完整的程序及其输出:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define IN_PREFIX      0x2b
#define OUT_PREFIX     "1.3."
#define ID_PREFIX_ERR  -1
#define ID_PREFIX_OK   0

int id_from_hexstring(char *out, char *in);

int main(void)
{
    char input[] = "2b06010201010300";
    char output[sizeof input * 2] = "";

    if (id_from_hexstring(output, input) == -1) {
        fprintf(stderr, "Error in input format\n");
    } else {
        printf("Input: %s\n", input);
        printf("Output: %s\n", output);
    }

    return 0;
}

/* Expects that out points to a suitably sized array containing an empty
 * string, and in points to a string containing only unsigned hex digits */
int id_from_hexstring(char *out, char *in)
{
    int ret_val = ID_PREFIX_OK;
    int offset;
    char *ptr = in;
    char val_str[3];

    while (sscanf(ptr, "%2s%n", val_str, &offset) == 1) {

        unsigned long dec_val = strtoul(val_str, NULL, 16);

        /* Handle prefix; return error code if invalid */
        if (ptr == in) {
            if (dec_val != IN_PREFIX) {
            ret_val = ID_PREFIX_ERR;
            break;
            } else {
                sprintf(out, OUT_PREFIX);
                ptr += offset;
                continue;
            }
        }

        /* Print next value to identifier string */
        size_t end = strlen(out);
        sprintf(out + end, "%lu.", dec_val);
        ptr += offset;
    }

    /* Replace trailing point */
    size_t out_len = strlen(out);
    if (out_len > 0) {
        out[out_len - 1] = '\0';
    }

    return ret_val;
}
Input: 2b06010201010300
Output: 1.3.6.1.2.1.1.3.0