[英]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++);
}
}
對於現在發現的將計數的十六進制字符串從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.