簡體   English   中英

將ASCII十六進制字符串轉換為字節數組

[英]Converting ascii hex string to byte array

我有一個char數組,說char value []={'0','2','0','c','0','3'};

我想將其轉換為字節數組,例如unsigned char val[]={'02','0c','03'}

這是在嵌入式應用程序中,所以我不能使用string.h函數。 我怎樣才能做到這一點?

在您談到嵌入式應用程序時,我假設您想將數字保存為值而不是字符串/字符。 因此,如果您只想將字符數據存儲為數字(例如整數),則可以使用sscanf

這意味着您可以執行以下操作:

 char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
 uint8 dest_val[3];                            // We want to save 3 numbers
 for(int i = 0; i<3; i++)
 {
     sscanf(&source_val[i*2],"%x%x",&dest_val[i]); // Everytime we read two chars --> %x%x
 }
 // Now dest_val contains 0x0A, 0x03 and 0xB7

但是,如果要將其存儲為字符串(如您的示例中所示),則不能使用unsigned char因為此類型的長度也只有8位,這意味着它只能存儲一個字符。 在單個(無符號)字符中顯示“ B3”不起作用。

編輯:根據評論可以,目標是將傳遞的數據保存為數值。 不幸的是,打開程序的編譯器不支持sscanf ,這是最簡單的方法。 無論如何,由於(我認為)這是最簡單的方法,因此我將保留答案的這一部分,並嘗試在此編輯中添加更多自定義方法。

關於數據類型,實際上是否有uint8都沒有關系。 即使我建議使用某種整數數據類型,也可以將數據存儲到unsigned char 這里的問題是,您傳遞的數據是一個字符/字母,您想將其解釋為數值。 但是,角色的內部存儲有所不同。 您可以檢查ASCII表 ,在其中可以檢查每個字符的內部值。 例如:

char letter = 'A'; // Internally 0x41 
char number = 0x61; // Internally 0x64 - represents the letter 'a'

如您所見,大寫和小寫之間也存在差異。

如果您執行以下操作:

int myVal = letter;  //

myVal 不會代表值0xA(十進制10),它將具有值0x41。

您不能使用sscanf的事實意味着您需要一個自定義函數。 因此,首先我們需要一種將一個字母轉換為整數的方法:

int charToInt(char letter)
{
    int myNumerical;
    // First we want to check if its 0-9, A-F, or a-f) --> See ASCII Table
    if(letter > 47 && letter < 58)
    {
        // 0-9
        myNumerical = letter-48;
        // The Letter "0" is in the ASCII table at position 48 -> meaning if we subtract 48 we get 0 and so on...
    }
    else if(letter > 64 && letter < 71)
    {
       // A-F
       myNumerical = letter-55 
       // The Letter "A" (dec 10) is at Pos 65 --> 65-55 = 10 and so on..
    }
    else if(letter > 96 && letter < 103)
    {
       // a-f
       myNumerical = letter-87
       // The Letter "a" (dec 10) is at Pos 97--> 97-87 = 10 and so on...
    }
    else
    {
       // Not supported letter...
       myNumerical = -1;
    }
    return myNumerical;
}

現在,我們有一種方法可以將每個字符轉換為數字。 另一個問題是總是將兩個字符附加在一起,但這很容易:

int appendNumbers(int higherNibble, int lowerNibble)
{
     int myNumber = higherNibble << 4;
     myNumber |= lowerNibbler;
     return myNumber;
    // Example: higherNibble = 0x0A, lowerNibble = 0x03;  -> myNumber 0 0xA3
    // Of course you have to ensure that the parameters are not bigger than 0x0F 
}

現在,所有的一切都將是這樣的:

 char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
 int dest_val[3];                             // We want to save 3 numbers
 int temp_low, temp_high;
 for(int i = 0; i<3; i++)
 {
     temp_high = charToInt(source_val[i*2]);
     temp_low = charToInt(source_val[i*2+1]);
     dest_val[i] = appendNumbers(temp_high , temp_low);
 }

希望我能正確理解您的問題,這對您有所幫助。

如果您有一個“適當的”數組,例如問題中聲明的value ,則循環遍歷它的大小以獲取每個字符。 如果您使用的是使用ASCII字母(很可能是ASCII)的系統,則可以通過將數字減去'0'來將字符形式的十六進制數字轉換為十進制值(請參閱鏈接的ASCII表以了解原因),並減去字母'A''a' (請確保沒有字母比'F'高),然后加十。

當您具有第一個十六進制數字的值時,然后以相同的方式轉換第二個十六進制數字。 將第一個值乘以16,然后加上第二個值。 現在,您具有一個字符形式的對應於兩個十六進制數字的單字節值。


是時候看一些代碼示例了:

/* Function which converts a hexadecimal digit character to its integer value */
int hex_to_val(const char ch)
{
    if (ch >= '0' && ch <= '9')
        return ch - '0';  /* Simple ASCII arithmetic */
    else if (ch >= 'a' && ch <= 'f')
        return 10 + ch - 'a';  /* Because hex-digit a is ten */
    else if (ch >= 'A' && ch <= 'F')
        return 10 + ch - 'A';  /* Because hex-digit A is ten */
    else
        return -1;  /* Not a valid hexadecimal digit */
}

...

/* Source character array */
char value []={'0','2','0','c','0','3'};

/* Destination "byte" array */
char val[3];

/* `i < sizeof(value)` works because `sizeof(char)` is always 1 */
/* `i += 2` because there is two digits per value */
/* NOTE: This loop can only handle an array of even number of entries */
for (size_t i = 0, j = 0; i < sizeof(value); i += 2, ++j)
{
    int digit1 = hex_to_val(value[i]);      /* Get value of first digit */
    int digit2 = hex_to_val(value[i + 1]);  /* Get value of second digit */

    if (digit1 == -1 || digit2 == -1)
        continue;  /* Not a valid hexadecimal digit */

    /* The first digit is multiplied with the base */
    /* Cast to the destination type */
    val[j] = (char) (digit1 * 16 + digit2);
}

for (size_t i = 0; i < 3; ++i)
    printf("Hex value %lu = %02x\n", i + 1, val[i]);

上面代碼的輸出是

Hex value 1 = 02
Hex value 2 = 0c
Hex value 3 = 03

關於ASCII算術的注釋:字符'0'的ASCII值為48 ,字符'1'的ASCII值為49 因此, '1' - '0'將得出1

使用strtol()很容易:

#include <stdlib.h>
#include <assert.h>

void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
    /** size 3 is important to make sure tmp is \0-terminated and
        the initialization guarantees that the array is filled with zeros */
    char tmp[3] = "";

    while (n--) {
        tmp[0] = *src++;
        tmp[1] = *src++;
        *dest++ = strtol(tmp, NULL, 16);
    }
}

int main(void)
{
    unsigned char d[3];
    parse_bytes(d, "0a1bca", 3);
    assert(d[0] == 0x0a);
    assert(d[1] == 0x1b);
    assert(d[2] == 0xca);
    return EXIT_SUCCESS;
}

如果不可用(即使它不是來自string.h),則可以執行以下操作:

int ctohex(char c)
{
    if (c >= '0' && c <= '9') {
        return c - '0';
    }
    switch (c) {
        case 'a':
        case 'A':
            return 0xa;

        case 'b':
        case 'B':
            return 0xb;

        /**
         * and so on
         */
    }
    return -1;
}

void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
    while (n--) {
        *dest = ctohex(*src++) * 16;
        *dest++ += ctohex(*src++);
    }
}
假設8位字節(實際上不是C標准保證的,而是無處不在),則“無符號字符”的范圍是0..255,而“有符號字符”的范圍是-128..127。 ASCII被開發為7位代碼,使用的范圍是0-127,因此,兩種`char'類型都可以表示相同的值。

對於現在發現的將計數的十六進制字符串從ascii轉換為無符號字節的任務,這是我的看法:

unsigned int atob(char a){
    register int b;
    b = a - '0';    // subtract '0' so '0' goes to 0 .. '9' goes to 9
    if (b > 9) b = b - ('A' - '0') + 10;  // too high! try 'A'..'F'
    if (b > 15) b = b - ('a' - 'A);  // too high! try 'a'..'f'
    return b;
}

void myfunc(const char *in, int n){
    int i;
    unsigned char *ba;
    ba=malloc(n/2);
    for (i=0; i < n; i+=2){
        ba[i/2] = (atob(in[i]) << 4) | atob(in[i+1]);
    }
    // ... do something with ba
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM