极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 44580|回复: 16

求助:如何将字节数组转换为十六进制字符串再转为十进制整数

[复制链接]
发表于 2014-2-26 20:34:35 | 显示全部楼层 |阅读模式
现在有一个字节数组,例如 char AA[6]={a,f,1,e,6,c} 代表的就是十六进制的 AF 1E 6C

如何把这个数组转换为十六进制的字符串,即 0xAF1E6C  ?
再怎么把它转为十进制的整数,即 11476588 ?

谢谢!

回复

使用道具 举报

发表于 2014-2-27 06:43:15 | 显示全部楼层
哈哈,你例子是一个伪命题,你那个定义AA方法是不存在的。
只有可能是下面两种情况:
第一种:
  1. char AA[6]={0x0a,0x0f,0x01,0x0e,0x06,0x0c};
复制代码
第二种:
  1. char AA[6]={'a','f','1','e','6','c'};
复制代码
第一种:
移位就行了

  1. unsigned long CharArrayToNumber( unsigned char *p_pBuff, int p_iSize )
  2. {
  3.         if( NULL != p_pBuff && p_iSize > 0 && p_iSize <= 8 )
  4.         {
  5.                 unsigned long ulRet = 0;
  6.                 p_iSize -= 1;
  7.                 for(int i=0;i<=p_iSize;++i)
  8.                 {
  9.                         ulRet |= ((unsigned long)(p_pBuff[i]))<<((p_iSize-i)<<2);
  10.                 }
  11.                 return ulRet;
  12.         }
  13.         else
  14.         {
  15.                 // arduino 有没有 throw 我不知道,异常肯定就挂了,怎么调试我也不知道
  16.                 //throw "CharArrayToNumber: arg error";
  17.                 return 0;
  18.         }
  19. }
复制代码
你的例子就写成:

  1. char AA[6]={0x0a,0x0f,0x01,0x0e,0x06,0x0c};
  2. unsigned long ulVal = CharArrayToNumber(AA,6);
复制代码
第二种:
就比较麻烦了,需要一个字符到数字的转换,估计你想要这个的可能性大

  1. inline unsigned long CharToNumber( unsigned char p_ucVal )
  2. {
  3.         switch(p_ucVal)
  4.         {
  5.         case '0':
  6.                 return 0;

  7.         case '1':
  8.                 return 1;

  9.         case '2':
  10.                 return 2;

  11.         case '3':
  12.                 return 3;

  13.         case '4':
  14.                 return 4;

  15.         case '5':
  16.                 return 5;

  17.         case '6':
  18.                 return 6;

  19.         case '7':
  20.                 return 7;

  21.         case '8':
  22.                 return 8;

  23.         case '9':
  24.                 return 9;

  25.         case 'A':
  26.                 return 10;

  27.         case 'B':
  28.                 return 11;

  29.         case 'C':
  30.                 return 12;

  31.         case 'D':
  32.                 return 13;

  33.         case 'E':
  34.                 return 14;

  35.         case 'F':
  36.                 return 15;

  37.         case 'a':
  38.                 return 10;

  39.         case 'b':
  40.                 return 11;

  41.         case 'c':
  42.                 return 12;

  43.         case 'd':
  44.                 return 13;

  45.         case 'e':
  46.                 return 14;

  47.         case 'f':
  48.                 return 15;

  49.         default:
  50.                 // arduino 有没有 throw 我不知道,异常肯定就挂了,怎么调试我也不知道
  51.                 //throw "CharToNumber: arg error";
  52.                 return 0;
  53.         }
  54. }
复制代码
这么写为了速度快,当然为了好看可以把 A 和 a 写一起,但写一起编译器恐怕不能优化成跳转,AVR的汇编我不了解,哪位了解可以看一下反汇编确定一下。
如果不确定,又追求效率,可以自己优化,给个思路:

  1. inline unsigned long CharToNumber( unsigned char p_ucVal )
  2. {        // 如果要用,具体 0 的数目对不对最好自己数清楚一下。。。
  3.         static const unsigned char __TransferArray[] = {0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15};
  4.         if( p_ucVal >= '0' && p_ucVal <= 'f' )
  5.         {        // 意思就是这一步在自己的代码里就保证了肯定是指针跳转
  6.                 return __TransferArray[p_ucVal-'0'];
  7.         }
  8.         else
  9.         {
  10.                 //throw "CharToNumber: arg error";
  11.                 return 0;
  12.         }
  13. }

  14. unsigned long CharArrayToNumber( unsigned char *p_pBuff, int p_iSize )
  15. {
  16.         if( NULL != p_pBuff && p_iSize > 0 && p_iSize <= 8 )
  17.         {
  18.                 unsigned long ulRet = 0;
  19.                 p_iSize -= 1;
  20.                 for(int i=0;i<=p_iSize;++i)
  21.                 {
  22.                         ulRet |= CharToNumber(p_pBuff[i])<<((p_iSize-i)<<2);
  23.                 }
  24.                 return ulRet;
  25.         }
  26.         else
  27.         {
  28.                 //throw "CharArrayToNumber: arg error";
  29.                 return 0;
  30.         }
  31. }
复制代码
你的例子就写成:

  1. char AA[6]={'a','f','1','e','6','c'};
  2. unsigned long ulVal = CharArrayToNumber(AA,6);
复制代码
=========================================================
ulVal 既是 0xAF1E6C 也是 11476588

  1. printf("ulVal=0x%X\n", ulVal);
  2. printf("ulVal=0x%ld\n", ulVal);
  3. // 输出:
  4. ulVal=0xAF1E6C
  5. ulVal=11476588
复制代码
不过你这个需求真的很奇怪,一个 char 的范围本身就是 0x00-0xFF 了
你那个AA为什么不是 char AA[4]={0x00,0xaf,0x1e,0x6c} ?

如果是大端系统就可以直接:

  1. unsigned long ulVal = *((unsigned long *)AA);
复制代码
小端系统0、3字节1、2字节交换后,就和上面一样直接强转。

大致就这么几种,根据你的情况用吧。总的来说 arduino 对性能的要求比较苛刻,
但效率主要取决于设计思路,具体代码的优化只能是毛毛雨。

arduino 是大端还是小端系统我还真没注意,测一下很简单:

  1. void TestEndian()
  2. {
  3.         static union {
  4.                 char _c[4];
  5.                 unsigned long _l;
  6.         } __endian_test = { 'l', '0' ,'0', 'b'  };

  7.         if( 'b' == ((char)__endian_test._l) )
  8.                 printf("是大端系统\n");
  9.         else
  10.                 printf("是小端系统\n");
  11. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2014-2-27 09:31:08 来自手机 | 显示全部楼层
膜拜一楼大神
回复 支持 反对

使用道具 举报

发表于 2014-2-27 10:30:33 | 显示全部楼层
补充一楼大神的,先上一段代码
  1. char s[]="0xA";
  2. int i;
  3. i = strtol(s, NULL, 16);
  4. printf("%d", i);
复制代码
使用strtol可以直接转化成十进制,百科中查下这个函数。你可以直接把AA作为参数放进来,楼主的AA定义是错的,得用1楼的第二种方式定义。
另外你要把AA变成0x开头的可以这样
  1. char tmpdata[32];
  2. sprintf(tmpdata,"0x%s",AA);
  3. //tmpdata中就是0xAF1E6C字符串了
  4. // 继续用strtol转换行了
  5. int i= strtol(tmpdata,NULL,16);
复制代码
sprintf    scanf   memset   memcpy 这四个函数还是比较有用的,前两个是对字符串操作,后两个是直接对内存数据操作,可以百科看一下
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-27 11:00:51 | 显示全部楼层
本帖最后由 lilho_e 于 2014-2-27 11:20 编辑

非常感谢 jytong ,转角 两位兄弟的回复。
我先消化一下,回头再来请教!
谢谢你们二位!

我的字符数组确实是类似
char AA[6]={'a','f','1','e','6','c'};这样的,里面只包含0-9 a-f,字母都是小写的。

实际上我得到的最原始的数据是 string 的字符串,就是类似 string data= "af1e6c........" 这样的,有100多个字符在里面,我自己再转换为char数组的。

这些数据是从传感器上传回的一系列的参数,一些参数占用1位(类似 c2 这样),一些参数占用2位 (类似 a3 c4),还有参数占用4位(类似 e3 c5 a2 22)

我想实现的功能就是用最快的速度,从一个 string 的字符串中,取出其中的某几位的数据 例如 "e3c5a222"来还原出十进制的数值(3821380130)。

顺带再请教一下,比如我要把这个数组清零,准备接收下组数据,语句是什么样的?

还有一个问题是:我现在是在开头就定义好数组的个数 ,比如 char data[120],如果定义成空的 char data[] ,程序运行第一次的时候,开始的几个参数总是存不进去。不知道是什么原因?
回复 支持 反对

使用道具 举报

发表于 2014-2-27 11:51:14 | 显示全部楼层
lilho_e 发表于 2014-2-27 11:00
非常感谢 jytong ,转角 两位兄弟的回复。
我先消化一下,回头再来请教!
谢谢你们二位!

数组清零你可以用memset函数
  1. memset(aa,0,aa占用的内存大小);
  2. //这句是把AA数组所用内存全部设置为0
复制代码
C语言中数组定义不能没有长度,必须指定长度。如果你想用个变长的字符串的话可以使用char* 这是指针,不建议新手使用,不及时释放会造成内存泄漏
回复 支持 反对

使用道具 举报

发表于 2014-2-27 12:02:05 | 显示全部楼层
另外你要截取字符串中间的某几位数据的话可以使用strncpy函数
  1. char data[]= "af1e6c........";//这里直接赋值时候是可以不写数组长度的,编译器会自动指定data长度的
  2. //要从第12位开始截取4个字符,出租是从0开始的还记得吧
  3. char dest[5];//要定义5个字符的长度才能保存4个字符 切记
  4. strncpy(dest,data+12,4);
复制代码
现在dest中就是你想要的数据了。别忘记字符串是用'\0'标识结束的,所以要定义5个  内存中保存的数据举例: a3c4\0  这就是内存中保存的数据
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-27 12:16:53 | 显示全部楼层
转角 发表于 2014-2-27 12:02
另外你要截取字符串中间的某几位数据的话可以使用strncpy函数现在dest中就是你想要的数据了。别忘记字符串是 ...

兄弟,非常感谢你耐心的回复,真是太谢谢了!
我来试一下!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-27 16:03:48 | 显示全部楼层
再次感谢楼上两位兄弟的回复。
现在找到一个简单的函数解决了:
unsigned long ulVal =strtol(data, NULL, 16);

data 是一个 char的数组,里面的内容类似 {"af1e6c........"} 只包含 0-9 a-f

这个函数的作用:直接将这个数组里的十六进制字符串转换为对应的十进制数值。
回复 支持 反对

使用道具 举报

发表于 2014-2-27 16:51:54 | 显示全部楼层
lilho_e 发表于 2014-2-27 16:03
再次感谢楼上两位兄弟的回复。
现在找到一个简单的函数解决了:
unsigned long ulVal =strtol(data, NULL ...

看来data数组中不需要加上0x开头是吧?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-27 18:00:31 | 显示全部楼层
转角 发表于 2014-2-27 16:51
看来data数组中不需要加上0x开头是吧?

是的,直接字符串就可以。
还有个问题想请教你一下:

strncpy(dest,data+12,4);

我现在有个数组 类似int Index[4,2]={14,2,25,3,35,2,60,4}这样

其中 index[n,0] 代表要取值的位置,index[n,1] 代表要取值的个数

用index来代替原来的 12 4 ,应该怎么写? 4好像可以直接用index[n,1] 来代替,12直接代替了要出错。

谢谢!
回复 支持 反对

使用道具 举报

发表于 2014-2-28 09:49:39 | 显示全部楼层
strncpy(dest,data+12,4);
这个data+12是表示从数组起始地址开始偏移12个字节。
data是数组名,+12是便宜12个字节。如果只写data的话就是访问的这个数组的起始地址(就是数组的第一个元素的地址)。
char data[]="abcdefghigkl";   // data长度是13
data其实就是"abcdefghigkl"的首地址,只写data得到的是'a'所在的内存地址值是0x3432dbac    data[0] 这就是取值,会得到‘a' .
data+3  相当于0x3432dbac+3   这是'd'的内存地址了。同理data+12你就从你的数组头部往后数12个单位就是了。
回到strncpy(dest,data+3,4); 中,就是把‘d’所在的地址作为第二个参数传进去,截取4个单位的长度
执行完之后 dest的值就是“defg"

你那边12代替进去出错,你检查一下data的长度有index[n,0]+index[n,1] 那么长吗?还有dest可用空间大小有没有小于index[n,1] +1

下面付上strncpy的源码
  1. char *strncpy(char *dest, const char *src, int n)
  2. {
  3.     char c;
  4.     char *s = dest;
  5.     if (n >= 4)
  6.     {
  7.         size_t n4 = n >> 2;
  8.         for (;;)
  9.         {
  10.             c = *src++;
  11.             *dest++ = c;
  12.             if (c == '\0')
  13.                 break;
  14.             c = *src++;
  15.             *dest++ = c;
  16.             if (c == '\0')
  17.                 break;
  18.             c = *src++;
  19.             *dest++ = c;
  20.             if (c == '\0')
  21.                 break;
  22.             c = *src++;
  23.             *dest++ = c;
  24.             if (c == '\0')
  25.                 break;
  26.             if (--n4 == 0)
  27.                 goto last_chars;
  28.         }
  29.         n -= dest - s;
  30.         goto zero_fill;
  31.     }
  32. last_chars:
  33.     n &= 3;
  34.     if (n == 0)
  35.         return s;
  36.     for (;;)
  37.     {
  38.         c = *src++;
  39.         --n;
  40.         *dest++ = c;
  41.         if (c == '\0')
  42.             break;
  43.         if (n == 0)
  44.             return s;
  45.     }
  46. zero_fill:
  47.     while (n-- > 0)
  48.         dest[n] = '\0';
  49.     return s;
  50. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-28 10:15:40 | 显示全部楼层
早上好,转角!感谢你如此详细的回复!希望以后能多多请教你!我的编程只是小白水平
你的回复让我对基本的概念又清晰了一些,我今天来学习一下指针的基本概念并试着运用一下。
很奇怪,我昨天用index数组来代替不行,今天早上可以了!可能是昨天哪里有错误没发现。
回复 支持 反对

使用道具 举报

发表于 2014-2-28 10:23:43 | 显示全部楼层
lilho_e 发表于 2014-2-28 10:15
早上好,转角!感谢你如此详细的回复!希望以后能多多请教你!我的编程只是小白水平
你的回复让我对基本的 ...

我是程序员,刚开始接触单片机,好多硬件的东西不太懂需要摸索,互相学习吧
回复 支持 反对

使用道具 举报

发表于 2014-2-28 10:27:11 | 显示全部楼层
学习C语言基础,建议你使用vc2005 或者vc6也可以,这编译器可以调试程序,让你能看到各个变量在运行时候都是什么值,也能查看内存、堆栈非常好用。目前最高版可能是vs2014了你没必要用那么高的版本,占用资源太大还慢
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-14 17:39 , Processed in 0.037446 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表