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

字节高低位转换的问题

[复制链接]
gaosmile 发布时间:2020-12-1 21:45
最近的协议中遇到字节高低位转换的问题,于是偷懒上网查看,遇到类似的问题,也认识一个新的名字,叫做蝶式交换
问题是这样子的
协议要求字节低位在左,高位在右,对每个字节做转换处理,逐个交换其高低位,例如11010001,经过0->7,1->6,2->5,3->4对应位的交换,变成10001011。
这里就需要有位操作的知识,参考 位操作运算有什么奇技淫巧?(附源码)
这里我们以8位数据高低位转换为例子:
1#include <stdio.h>: }+ a0 x1 x6 R. ?* Q; @. X
2
; S% x1 D  a. ^& F8 r/ ?" v! a 3unsigned char highAndLowShiftHEX(unsigned char data);9 J/ m6 ?* k' y" n1 s4 C
4void printBin(int n);( G9 k* S7 B! V7 W! F8 X
5
* X) y: z. Q3 B" y4 X; v 6int main () {6 R4 U+ F# J+ F% q; N3 O% V' O& k
7% W/ ~  l0 O. ]% H5 l+ A
8    highAndLowShiftHEX(209);! v* n5 I" l. H6 h5 z
9    return 0;
% j. w& n8 ^4 }9 v0 Z10}
  x' j- B3 y$ B. A$ F2 _11
  b! o% r3 o( j! {12unsigned char highAndLowShiftHEX(unsigned char data)  ; ^- G( X* b+ m1 h9 C& @
13{  0 q% p+ n6 N- ^# Q5 l2 x
14   unsigned char i;  
; k9 ?9 [4 ]& h: N' I15   unsigned char tmp=0x00;  
$ \: v6 b* \" X' i" \' z16   for(i=0;i<8;i++)  
: i- }  L4 \+ R% b1 |17   {  5 T" a6 u; [3 V. x; o
18       tmp=((data>>i)&0x01)|tmp;  ! i0 K4 W+ k9 {' ?
19       //printBin(tmp);
0 B8 }1 g3 _) E0 U- g$ I5 u& H20       if(i<7)  2 }! j# [* T# `) o9 E; a
21           tmp=tmp<<1;  
! D5 Z2 P) r0 W* ~& f9 Z+ U22   }  9 r# |" J* ^. K3 G7 h
23   printf("\nafter shift data:");  
. I  ~9 |% K- r. S24   printBin(tmp);
5 V8 a& |" Y3 T" M, Q% B$ P: o6 O/ \25   return tmp;   
$ `5 Q+ V7 _: y& s, J26}
  }5 K4 e  s# v8 G; Y27; A/ T6 L; y$ q# N* ^
28//由于二进制直观,故写了一个打印二进制的函数
/ k, D5 G  q' r) H: d29void printBin(int n)
# [; e0 H- J# \+ b. y: L) C. B30{
2 s- g0 ]" s. q* ?+ K9 B  R31    int len = sizeof(n)*8;//总位数。
' p5 I8 {! s; M1 W+ W; n  V32    int i;, F( i2 S7 @6 A5 o- D. Z$ e" N( g; }+ T  |
33    if(i == 0)* }5 N" ^0 G9 u% P9 X' \( H6 Y$ y
34    {
/ j0 z0 O4 r( Y: p1 C35         printf("0");
2 R8 U9 U7 t2 Q$ [0 O- Y36         return;8 _! z0 k8 N, ?* E
37    }9 u9 @" r, m: j  \+ T: H- X
38    for(i = len-1; i >= 0; i --)//略去高位0.; r# ^6 @6 w- d3 W
39    {
% x, `1 O! a9 n9 u% X! b40        if(n&(1<<i)) break;1 y2 e( |& W' @0 L$ f% F
41    }0 V) o; @6 a. U$ n
420 Z5 n1 r3 J& O/ Z0 e
43    for(;i>=0; i --)
  K3 H7 [) K7 |/ i+ j44        printf("%d", (n&(1<<i)) != 0);
. X$ Z+ y' ^8 |% j. d) q& P5 [45}
, V5 M2 f4 n9 u; f2 t
熟悉位操作,上述代码实现起来就比较简单。在嵌入式开发中这类问题通常使用蝶式交换法和查表法来实现。
高阶实现?
查表法就是将一些值存到内存中,在需要计算的时候查表,但是这种方法会占用额外的存储空间。
所以这里主要介绍一下蝶式交换法,我们以8位数据转换为例。
  • 假设原始序列为:1 2 3 4 5 6 7 8
  • 目标序列为:8 7 6 5 4 3 2 1

    0 z: R5 l+ J9 u/ A8 o% n
那么流程图如下:
微信图片_20201201214414.png
由此完成了整个位的逆序转换,同样以11010001为例,下面是具体的实现代码:
1#include <stdio.h>
3 k8 e: ]2 }& R4 A6 h 2
. J' `( v+ G, H! w' F' L& P 3unsigned char highAndLowShiftHEX(unsigned char );. s+ s- r& Y: j& I6 f  O
4void printBin(int );
  [) w  {- T- p4 g) i( M 5
) \7 L  `! X' v( P 6int main () {
- \* [2 c: Y* M# r3 o 7
4 e" f2 e( U( A# Z5 j 8    highAndLowShiftHEX(209);
& X+ J' }9 C4 ` 9    return 0;0 R' t7 S! D. v0 K
10}
0 R# x+ U: y( u5 d& x3 @11
' u3 [8 y, b% |: K" i/ o12unsigned char highAndLowShiftHEX(unsigned char data)  
5 E/ @. R: w/ e# O: v13{  3 ]( `7 [# A6 i. \
14   data=(data<<4)|(data>>4);  
& F1 I9 j) Z. W15   data=((data<<2)&0xcc)|((data>>2)&0x33);  
' c3 A3 i+ Q; c# I16   data=((data<<1)&0xaa)|((data>>1)&0x55);  
/ Z' p1 Y: _' O/ [17   printf("  after shift data=%x \n",data);  
5 ]7 z* q# k% M- c* l9 c18   printBin(data);
3 f* N) M" @" [& z$ M  M19   return data;  - q6 X+ n$ {% T, M( l
20}& m- a# Y& d/ }9 d  D& S$ Y
21! [8 E4 l. F: q4 k; l
22//由于二进制直观,故写了一个打印二进制的函数' ]: O2 V  i$ k% |
23void printBin(int n)
; Y# E: `6 b8 N/ H! T) c& M7 m4 X24{
5 t/ Z9 w9 M, O' C8 }* s25    int len = sizeof(n)*8;//总位数。
1 G' S7 P2 S: A26    int i;
6 @! X, C4 r) T' N27    if(i == 0), [3 k4 I7 Y& ?* z% _+ _- q
28    {
# V2 T: s0 D  y% a0 @- |! n29         printf("0");; L8 \9 N$ h5 A
30         return;
1 ]( Z1 D, g6 d. }7 b% B31    }% c: D, B9 B5 j9 B, l
32    for(i = len-1; i >= 0; i --)//略去高位0.
: F6 K" _# ~( q4 F5 n1 x' \* ^) r33    {
$ \, W/ o1 z9 x1 x3 T2 J, t8 B34        if(n&(1<<i)) break;
% A# b7 {, I  e9 z( J35    }
; F5 L+ I! p7 C* p& Q36
% C$ X) _% \( k' x37    for(;i>=0; i --)/ N& o* y) J, y' L6 o+ Y4 q
38        printf("%d", (n&(1<<i)) != 0);
3 a0 ^9 i* ^; Z0 t39}3 j  [* O9 s$ k: s
交换字节的高低位并不是一个很常见的问题,遇到该问题时,需要经过仔细的分析,加上对C语言位操作的熟练掌握,就能够很好的解决这一类的问题。
扩展
那么我们将其扩展到16位半字数据的高低位转换。
其实原理是跟8位的时候是一样的,采用简单的移位方式对数据的高低位进行转换。熟悉位操作的话代码就相对简单了。
下面是对该思路的具体实现。
1#include <stdio.h>
: _6 S1 s& @) h3 G$ F 2
5 n( {7 M) E: V/ T 3void expandPrintBin(int val2);
& J9 I: n1 ?, }1 U3 l, _7 ^; i' c 4unsigned short HighAndLowSwitchHEX(unsigned short data);
( |- b& E% A* O, _  ^- A' p6 t+ g6 h 56 [3 B% y  K$ B- N& ^. f
6int main () {
9 ~& M' i6 M' D" E) L: J 7
1 S2 m  I1 K  X7 T; ? 8    HighAndLowSwitchHEX(38491);
  B" x0 a4 Q8 h- V2 S 9    return 0;
: E6 C; k& p4 O6 z7 T$ G10}- j0 B" }8 I/ @0 Y; T6 E3 p( a
11/ g* J$ x: t! @  [
12  x4 \0 m+ o9 f4 L' p. c$ A
13//由于二进制直观,故写了一个扩展的打印二进制的函数
. A/ R/ }% B  Y9 a: n, f' d14void expandPrintBin(int val2)3 ?' ?' o" L8 t3 H# |4 |7 F( W
15{2 N- J* T8 N& ]* I2 u) M" z* u
16    int i,k;) j/ Q% {- D/ n1 y. L) e9 ^
17    unsigned char *p = (unsigned char*)&val2 + 3; //从低位到高位,低端字节计算机& e* |& p5 y' e( N9 S9 U4 w. K; t
18    for( k = 0; k <= 3; k++)  `8 ]# A6 F( _# R& {
19    {' B# ]" H. |) ^, p, p+ v
20        int val2 = *(p-k);8 ]; D% e  V. \+ ^) d% C' Q
21        for (i = 7; i >= 0; i--)- x& F4 q. I* ~4 Q' C
22        {  l% ]- v" I! x& r) B1 l
23            if(val2 & (1 << i))
( ?" k" V& J# E" w! E24                printf("1");
4 J% G: p' U0 ^25            else+ G! F# k3 ]8 }  x5 E
26                printf("0");. i; \  B# Y* s8 N6 S0 S  b2 d
27        }
- |; C6 R( {. j28        printf(" ");+ p# r, ]* c8 h: X4 S
29    }
5 S4 p) [3 n7 |" w: L30}
1 D5 R8 }- M6 U$ z3 p: R4 p5 _31unsigned short HighAndLowSwitchHEX(unsigned short data)
7 g7 p: y# g6 G1 `32{# A: s) X+ a; d. G
33    unsigned char i = 0;
( ?) J! R/ X' J; p$ y- p9 i4 w34    unsigned short temp = 0x0000;0 b. ?, ]) o+ o3 u0 e8 l7 a* s
35
* h' i, i: r1 v36    for(i = 0; i < 16; i++)
2 _5 K& \5 [8 Q& Q- d37    {, D! o5 V$ Z. s8 _2 M
38        temp = ((data >> i) & 0x0001) | temp;
+ [0 y& K+ }" @% I' @/ O1 L39        if(i < 15)
0 E" p  ~4 R9 ?" }0 _7 x1 Y: X40        {8 `7 q- r; B: h: t5 b$ V% @4 d% d( B' N
41            temp = temp << 1;6 j& T9 d% [5 {, N2 l: ^- w
42        }  n4 l) A/ b0 }& ^6 o& g0 H
43    }
; p+ E$ H% ?# u6 E44    printf("temp:%x\n\n",temp);2 d$ v  o1 k5 _
45    expandPrintBin(temp);' W1 l: F! o( T4 L* m
46    return temp;  K: l7 g: ]# |9 O; ^# ^
47}' L% \" G1 Q5 G6 g0 d
同样的所谓的蝶式交换法,我引用了字节交换法的例子,我们可以演算一下:
  • 假设原始序列为:a b c d e f g h i j k l m n o p
  • 目标序列为:p o n m l k j i h g f e d c b a

    3 @7 o& T& @4 V& R9 S4 _
那么流程图如下:
微信图片_20201201214417.png
由此完成了整个位的逆序转换,完成了算法的拓展,以1001011001011011为例,下面是具体的实现代码:
1#include <stdio.h>2 t1 a* r0 I! f, ?
2
# ~) o/ L9 b# L3 \5 z 3unsigned short highAndLowShiftHEX(unsigned short data);- {9 H" U9 s1 G: T9 h
4void expandPrintBin(int val2);9 a3 S9 o5 N2 U1 c5 i0 ?
5! S4 Z* i5 \& D
6int main () {
6 g% ]* A$ X( J6 I: o 7* u1 I7 ^0 C* u7 T# n; c2 p7 q  F
8    highAndLowShiftHEX(38491);
' ~4 }+ {) D1 y9 V! e% E# y: |* B/ v 9    return 0;
; R4 `7 o( T1 y3 z10}
6 H2 H! N9 a& ?- L" D8 u112 z8 i$ u; B- l9 o) _( ^% _
12unsigned short highAndLowShiftHEX(unsigned short data)- L- ?. F- j" `* k2 ?8 E! [0 w5 J
13{0 n. v; L. }( a, s- Y
14  data = (data << 8) | (data >> 8);   //01011011100101105 Y+ y! D) R2 q- V+ k4 j! @5 ?# q
15  data = ((data << 4) & 0xF0FF) | ((data >> 4) & 0xFF0F); //1011010101101001
% N: _; M: l9 o16  data = ((data << 2) & 0xCCCC) | ((data >> 2) & 0x3333); //1110010110010110
/ l) A6 Z- Q# Q17  data = ((data << 1) & 0xAAAA) | ((data >>1 ) & 0x5555); //1101101001101001
$ G+ v) Z+ t5 m( r18  printf("  after shift data=%x \n",data);  
% k" s* q' V7 p! c19  expandPrintBin(data);" m' Z' a: R3 W+ Z
20  return data;  1 |6 e/ N2 A. \1 I+ Y
21}. a- F. w4 b6 T3 u3 `3 ?, \& V
22& l/ k' B( T0 C+ i( P
23//由于二进制直观,故写了一个扩展的打印二进制的函数
: ]  C/ n5 `; b2 p24void expandPrintBin(int val2)
3 W% e- s/ |- L25{1 n$ h2 E, y; J
26    int i,k;
- z( r  [0 R/ x' i- u, R, e# S% k# b27    unsigned char *p = (unsigned char*)&val2 + 3; //从低位到高位,低端字节计算机4 r4 B/ o. M  w- k
28    for( k = 0; k <= 3; k++)
# j3 G% P+ @# w29    {
% F/ _# G- a1 X8 \30        int val2 = *(p-k);% n$ w% [4 h. m. p9 k
31        for (i = 7; i >= 0; i--)  D% j( a3 [2 @8 R
32        {
5 i3 q* c9 v4 d( Q7 Q! M33            if(val2 & (1 << i))5 J& S. @( }, ^8 y1 U! S9 D
34                printf("1");" d* a, P# G2 J1 R. I
35            else
5 v  B, @4 f( B) ]; v$ v36                printf("0");* ~. x2 l. c+ _) T, _- I+ }7 @) _$ i
37        }
, x" \* z" U! ?0 U, `$ `4 U38        printf(" ");
: {8 ?  n( q) z, Y8 a7 Q39    }
  R- w! |: y9 O  }( t, w40}
7 Q* i' X, x$ ^: J: o' y
对于这种交换位的问题,在嵌入式开发中会经常遇到,熟悉掌握位操作还有调试手段很重要。熟练的利用好C语言的移位操作,就能快速的解决此类问题。
总结
上面的问题关键还是位操作的灵活妙用,其次是写了两个打印二进制的函数,方便使用,代码可以直接使用,调试不易,欢迎点赞,在看,转发也是厚爱,我们下一期,再见!
1 \" I8 q$ B# U% v0 G
赞 收藏 评论0 发布时间:2020-12-1 21:45

举报

0个回答

所属标签

相似技术帖

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