你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

快速互转 HEX (16进制) 方法——适合 MCU 用的 C语言

[复制链接]
gaosmile 发布时间:2020-3-19 13:51
缘由
$ ~2 E7 m/ W" y这个起因是昨晚群里有人在讨论怎么把字符串转成
HEX方法最佳,讨论到最后变成哪种方法效率最优了。毕竟这代码是要在MCU上面跑的,要同时考虑到时间和空间的最优解。
( z4 A( _6 I8 }0 s
当然讨论的是有结果的,具体实现的方法和代码在下面展示。
char数组转16进制HEX串
5 ~! K! ]% ?4 }' s. i" c& x3 W; j例子:

9 \1 f2 l& \5 p  n0 j* j将如下的量
8 N; l0 m& W3 U  ^. R
  1. ; m1 C% M4 U5 A& d$ |8 l' {4 g
  2. char str[] = "12345";  n9 p* A7 ^& K
  3. char data[] = {1,2,3,4,5,0xff};
复制代码
; z, K! {  u4 p" \6 R
转成! U8 D4 n- a# W* l1 t$ f) M: _. z( z1 A+ @  t

  1. 2 F9 T! Y2 @0 O: v
  2. "313233343500"$ z) b5 |% v. D7 V4 ?9 m
  3. "0102030405FF"
复制代码
1 W4 Y) ^3 v1 Y, G
这样的结果1 Q+ R; P6 I, v* n& [: J
这个其实很简单,追求速度的话,查表就好了
( I/ ]; s  P0 Z" h) X! E/ q( c# P) _9 M
从
0-16对应0-F即可:% G! T+ ^( [! k
  1. $ X* I9 O# t+ e( j
  2. const char hex_table[] = {
    , k% A; i5 @9 ~# L
  3. '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    + p, g9 C7 a6 A
  4. };
复制代码
. e# p5 O# O4 V0 m
然后一个个从表里取出来,拼到对应位置即可:
1 F6 y3 k/ q. {( e$ j. p! x0 ?
  1. . K( W$ q) R3 h1 w
  2. void to_hex(char *s, int l, char *d)5 g! d7 b) o% Y5 T5 G& J& U
  3. {# x! \0 R& {+ t9 F2 B
  4.     while(l--)  x9 `9 [3 ^  w" d4 a
  5.     {
    : p3 d9 u4 l  Z' z0 {, Y: B7 D
  6.         *(d+2*l+1) = hex_table[(*(s+l))&0x0f];
    3 Q2 _+ T/ g3 {1 W& r2 t
  7.         *(d+2*l) = hex_table[(*(s+l))>>4];
    $ p3 \7 {& k0 v4 v$ T' Z; `% {
  8.     }
    , [4 g" P8 D5 r/ C3 r) w$ o
  9. }
复制代码

: u8 t; R$ z2 }完整测试代码如下:# G3 b7 D5 K2 {- G
  1. # Q3 ~: P) y$ g! K
  2. #include <stdio.h>! |0 G, |3 ]7 s! |& t% a8 F1 m
  3. const char hex_table[] = {
    ; u: P% \; a4 @
  4. '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    7 W& w2 a7 v  l2 W$ W& N( U" F0 @8 R& F
  5. };7 G  f6 @8 A! A; {2 d" f5 J3 i
  6. void to_hex(char *s, int l, char *d)( j( x, s0 _9 S5 S! B. w0 N1 e5 o+ t0 c
  7. {/ C/ c! I3 u* z6 T' A- p9 }8 j3 |( I
  8.     while(l--)$ Y! Q4 l; j8 l  X1 }# M# `' n
  9.     {8 Y2 s, ]1 g( V
  10.         *(d+2*l+1) = hex_table[(*(s+l))&0x0f];
    ) L+ ?2 {1 n5 V- t# M2 F- E
  11.         *(d+2*l) = hex_table[(*(s+l))>>4];# q) |$ g( f: ]: Z
  12.     }4 v6 U2 f9 O! p) b5 k7 G
  13. }: |8 n8 W; p, j
  14. int main () {( z9 O, ^9 `, _/ |; e9 j
  15.     char s[]= "1234";
    " u! Y9 ]* Q& e* l6 x. p  {. {
  16.     char d[9];4 p) |5 Q/ \) y: p5 k! j" \
  17.     d[8] = '\0';
    0 o0 C4 V+ G* W6 N- x  `" ?
  18.     to_hex(s,4,d);/ T3 J6 [1 H( }% ]! D' k
  19.     printf("%s",d);
    / Z. W0 q8 C+ u, \6 |4 `
  20.     return 0;
    ' g" D1 V" E1 R4 f
  21. }
复制代码

- j+ M+ `6 z' i5 g& ~! V9 U7 `输出结果:3132333416进制HEX串转成数值数组
. F6 k# G# j6 @; z例子:

6 Q# l1 h  k/ ~% x* X: k7 s* @将类似
"AAbb2fFF"的量转成{0xAA,0xBB,0x2F,0xff}这样的结果
$ d, R5 i8 t: X2 W7 b! w- E
这里如果还用查表的话,这个rom占用会浪费掉不少空间,所有查表法直接就被否决掉了(如果是PC上,追求极致速度的话,当然可以用)。

* l. u: G# E; P, \9 T: N同时,为了通用性,代码需要兼容大小写两种输入数据* X9 K) t5 h1 W: L

1 Q* W& O+ z3 C& P* ~4 H: [0 W
在仔细研究数据的结构时,我发现了个规律:  V" t  h  _5 I: T" H

4 X3 O/ `6 l# j2 c& ?8 J; GASCII中的
0-9对应了0x30-0x39
" I8 V* V  X2 d" X7 @9 Y$ SASCII中的A-F对应了0x41-0x46
9 I8 E" k# m4 g# n9 U0 e* @- EASCII中的a-f对应了0x61-0x66
! ?; r: k0 W& `4 X. n  T
也就是说,只要这一个字符大于
0x39,那它一定是字母;同时,在上面的分析也可以发现,如果这个字符是字母,不论大写小写,只需要看低四位就可以直接判断这个字符代表的数是多少2 f8 M' v, U* ]8 G$ S
- ~# v" w/ G& L) z1 H1 l, G
具体逻辑如下:: O& N4 a% |: ^2 K& V6 f" g1 N
# v! [- t) A4 t' u1 O
判断这个字符是否大于0x39
  S1 |$ t3 n; s5 v" A. ~
/ N( C9 S6 I, ^0 t8 o. Z6 l' e
如果不是,直接取这个字符的低四位当作结果
  ^1 s# _1 s. a( H5 B& B& t' V8 B; F
如果是,则为字母,将他的低四位加上
9即为所需结果
& f* u0 @0 x7 n8 W) N
具体实现代码也如下:
/ B+ H; ~; y: i/ y

  1. & j( l, _" v8 p( V+ ^1 H- Q0 M4 V
  2. void from_hex(char *s, int l, char *d)
    ! E: X* m9 K3 \, n
  3. {
    9 l1 i7 z) S# t( G9 m
  4.     while(l--), M% ^9 ]  o, \0 A$ I$ Y6 E
  5.     {( u5 c, g& p: q( E( Y/ E& C
  6.         char* p = s+l;  j; ?% _0 c% w' b' j7 g/ Z
  7.         char* p2 = p-1;
    ; D6 S0 R3 Q: F( R
  8.         *(d+l/2) =6 F1 w& T7 L$ G; ]
  9.         ( (*p>'9'? *p+9 : *p) & 0x0f ) |
    * ^5 @; M7 f$ v2 l
  10.         ( (*p2>'9'? *p2+9 : *p2) << 4 );, {7 u8 @+ W! }7 y
  11.         l--;2 V: L/ F* {1 q: u
  12.     }
    4 d6 X) D6 j. M& p) g- h5 b# i5 Q2 z
  13. }
复制代码

+ q5 v! q9 {% z$ b6 x1 S& B

$ ~" a7 A1 w/ A" P' ^8 o+ i. Y. A9 m* J/ V
完整的测试代码
: N  t" l- t7 d7 t* m6 L& b
  1. <font color="#003000">
    ; k" a& F8 v0 J, [
  2. #include <stdio.h>
    1 M  f5 a# O3 J: o2 K3 B
  3. void from_hex(char *s, int l, char *d)
    # n* w* O& j' r. u$ b. c) X) m
  4. {" h- V* j' s& N% O
  5.     while(l--)2 b/ T. |5 B% N& L: i
  6.     {/ S/ P4 R+ o6 }7 {: |
  7.         char* p = s+l;
    - `5 c) Z/ R* |3 j9 a' q3 Q4 M
  8.         char* p2 = p-1;
    0 _( C" p) J- |# |% u
  9.         *(d+l/2) =
    3 K/ w( R4 z) S/ R" s5 I  J5 g, M+ q
  10.         ( (*p>'9'? *p+9 : *p) & 0x0f ) |' t7 @% F3 W/ h9 C
  11.         ( (*p2>'9'? *p2+9 : *p2) << 4 );) ^* e2 K  H/ M% P! \9 w0 m
  12.         l--;2 ~8 H& M% L9 O8 F, z0 y0 ~2 W; h8 ?
  13.     }, ?  e1 {! ~- t+ V: J5 {1 w
  14. }
    , A6 _: E. d6 M( O
  15. int main () {+ B' H" F1 S" ], d1 ^
  16.     char s[]= "6F6B6f6b";& q6 ?0 t' x0 q2 h7 h
  17.     char d[5];
    . y& \, G+ \, G
  18.     d[4] = '\0';2 o$ f' s& J% {7 t
  19.     from_hex(s,8,d);  M/ }5 t$ E7 I2 t$ J1 z
  20.     printf("%s",d);
    3 i# t/ X; R4 S6 {
  21.     return 0;
    ) ?* G& t9 b( ?
  22. }</font><font color="#003000">
    $ C, j% G& s2 I- n. \
  23. </font>
复制代码
输出结果:okok, K0 w# |% Y% b5 v; h

1 L  z- \7 }7 b; s7 r如果你有更好的方法,欢迎在留言讨论!
赞 收藏 评论0 发布时间:2020-3-19 13:51

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版