我有一个char数组说char value []={'0','2','0','c','0','3'};
我想将其转换为像unsigned char val[]={'02','0c','03'}
这是在嵌入式应用程序中,所以我不能使用string.h函数。我怎么能这样做?
答案 0 :(得分:4)
这意味着您可以执行以下操作:
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 Table,在那里可以检查每个字符的内部值。
例如:
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);
}
我希望我理解你的问题,这有助于......
答案 1 :(得分:3)
如果你有一个“正确”的数组,比如问题中声明的value
,那么你就可以遍历它的大小来得到每个字符。如果您使用的是ASCII字母表(最有可能)的系统,则可以通过减去数字'0'
将字符形式的十六进制数字转换为十进制数字(请参阅链接的ASCII用于理解原因的表格,并为字母减去'A'
或'a'
(确保当然没有字母高于'F'
)并添加10。
如果您拥有第一个十六进制数字的值,则以相同的方式转换第二个十六进制数字。将第一个值乘以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
。
答案 2 :(得分:2)
使用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++);
}
}
答案 3 :(得分:1)
对于现在发现的将计数的十六进制字符串从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
}