分享

CRC16校验 模二除法

 erbiaoge 2015-04-30
  1. //  
  2.   
  3. /*写在最前面 
  4. 我看了几个CRC16校验的源代码,发现它们都是直接使用数值来进行计算的,那样的话输入不是很方便,你得直接 
  5. 输入八个二进制数对应的十进制数,并且能够校验的只是8*n个二进制数,不过那种有一个好处,计算速度快,并且 
  6. 需要的内存空间也小。 
  7. 我没按照那种方式来进行计算了,我把二进制的表示放到了一个字符串里面,也就是字符串里面的每一位表示一个二进制数, 
  8. 比如二进制的110就用字符串"110"来表示,并且这个CRC16的校验是使用模2除法来弄的。 
  9. 这种方式的有点就是你可以输入的M的长度随便,而且是直接输入01组成的二进制数,当然缺点就是牺牲了效率。 
  10. 写了一个通用的模2除法函数,传入字符串表示的二进制的被除数、除数就能够得到商和余数(CRC16的时候商是没有用的), 
  11. 这个函数可以给你显示出每一步的计算过程,如果你想看看它的计算过程的话,你把下面宏定义的SHOWPROCESS的值改为1就可以 看到, 
  12. 这个函数我没有怎么去验证它是否正确,我自己随便举了几个数据计算,手算和它算是一样的。我用它计算了一下你们课本上的 
  13. 那个,结果是一样的(如果开了显示过程的话,过程也是一样的)。 
  14. 如果你不懂模2除法的计算过程的话你可以把显示计算过程开了(把下面宏定义的SHOWPROCESS的值改为1就可以),多举几个 
  15. 数字进行计算,看看过程就可以弄懂的,显示计算过程也就是为了这。 
  16. 因为没有直接对字符串表示的二进制进行异或的操作,因此就写了一个strxor来实现,它传入异或结果保存的空间和两个操作数就可以 
  17. 得到结果。 
  18. 讲讲什么是异或吧,异或就是相异(不同)的时候为1,相同的时候为0,比如 
  19. 1xor0=1 
  20. 1xor1=0 
  21. 0xor1=1 
  22. oxor0=0 
  23.  
  24.     01010 
  25. xor 10100 
  26. =   11110 
  27.  
  28.  
  29. CRC16得到FCS和原来的M组到一块就是带校验帧的数据,你把这个数据在进行一次CRC16得到的FCS应该为0,这点我检查过多次,是正确的。。。:) 
  30. 是努力的按照你们课本上的意思来实现的了,但是也有可能有错误。。。。。。 
  31.  
  32.  
  33. 哦,提一下,输入的时候你就只输0和1就行,我没有做容错检查,其它的什么非01的字符就别尝试输入了,别为难机器。。。 
  34. 不懂的问我,我今早没课的! 
  35.  
  36. 最后呢,早安、学习快乐! 
  37. */  
  38.   
  39.   
  40. #include <iostream>  
  41. #include <string.h>  
  42. using namespace std;  
  43.   
  44. #define SHOWPROCESS 0   //这个宏定义来控制是否显示模2的计算过程,值为0的时候不显示,值为1的时候显示  
  45.   
  46. //该程序中二进制数用字符串表示,比如二进制的110就用"110"表示  
  47.   
  48.   
  49. //该函数完成二进制数的异或  
  50. //result保存异或的结果,s1和s2为两个二进制串  
  51. char* strxor(char *result, const char *s1, const char *s2)  
  52. {  
  53.     int i=0;  
  54.     while(s1[i] && s2[i]){  
  55.         if(s1[i] != s2[i]){ //相异的时候为1  
  56.             result[i] = '1';  
  57.         }  
  58.         else{   //相同则为0  
  59.             result[i] = '0';  
  60.         }  
  61.         ++i;  
  62.     }  
  63.     result[i] = '\0';   //字符串结束  
  64.     return result;  
  65. }  
  66.   
  67.   
  68. //将字符串左移一位  
  69. //传入字符串本身,返回字符串本身  
  70. char* strlmv(char *s)  
  71. {  
  72.     int i=0;  
  73.     while(s[i]){  
  74.         s[i] = s[i+1];  //前一个等于后一个  
  75.         ++i;  
  76.     }  
  77.     return s;  
  78. }  
  79.   
  80.   
  81. //重复n次打印字符c  
  82. //传入需要重复打印的字符c以及需要重复的次数  
  83. void repeat(char c, int n)  
  84. {  
  85.     while(n--){  
  86.         cout<<c;  //重复打印  
  87.     }  
  88. }  
  89.   
  90.   
  91. //该函数完成模2除法  
  92. //传入参数:被除数 除数 保存商的空间 保存余数的空间  
  93. void strm2div(const char *strM, const char *strP, char *strQ, char *strR)  
  94. {  
  95.     int lM = strlen(strM);  //被除数的长度  
  96.     int lP = strlen(strP);  //除数的长度  
  97.     int L = lM+lP;  //被除数和除数的总长  
  98.     int i;  //循环需要的  
  99.   
  100.     char *sM = new char[L+1];   //使用sM替换被除数,前lM个值为除数本身,后lP个值用0补上  
  101.   
  102.     for(i=0; i<L; ++i){  
  103.         if(i<lM){    //前lM个值为除数本身  
  104.             sM[i] = strM[i];  
  105.         }  
  106.         else{   //后lP个值用0补上  
  107.             sM[i] = '0';  
  108.         }  
  109.     }  
  110.     sM[i] = '\0';   //字符串结束  
  111.   
  112.     strncpy(strR, sM, lP);  //一开始余数照搬被除数  
  113.     strR[lP] = '\0';    //字符串结束  
  114.   
  115.     #if (SHOWPROCESS==1)    //如果需要显示计算过程的话  
  116.         cout<<strM<<'/'<<strP<<"的计算过程:"<<endl;  
  117.         cout<<sM<<endl;     //显示出被除数  
  118.     #endif  
  119.   
  120.     for(i=0; i<lM; ++i){  
  121.         #if (SHOWPROCESS==1)    //如果需要显示计算过程的话  
  122.             if(i!=0){   //第一次的话不用输出余数(已经除数了被除数了)  
  123.                 repeat(' ', i);     //先重复打印i个空格进行对齐  
  124.                 cout<<strR<<endl;   //打印余数  
  125.             }  
  126.         #endif  
  127.   
  128.         if(strR[0]=='1'){   //如果余数最高位为1  
  129.             #if (SHOWPROCESS==1)    //如果需要显示计算过程的话  
  130.                 repeat(' ', i);     //先重复打印i个空格进行对齐  
  131.                 cout<<strP<<endl;   //打印除数  
  132.             #endif  
  133.   
  134.             strxor(strR, strR, strP);   //余数与除数做异或,异或后的值直接更新到余数  
  135.             strQ[i] = '1';  //商1  
  136.         }  
  137.         else{   //如果余数高位为0  
  138.             #if (SHOWPROCESS==1)    //如果需要显示计算过程的话  
  139.                 repeat(' ', i);     //打印i个空格  
  140.                 repeat('0', lP);    //重复lP个0(因为余数高位为0)  
  141.                 cout<<endl;  
  142.             #endif  
  143.               
  144.             //这里应该是与lP个0做异或,因为和0做异或等于本身,因此略去  
  145.             strQ[i] = '0';  //商0  
  146.         }  
  147.         strlmv(strR);   //把余数左移(最高位丢弃)  
  148.         strR[lP-1] = sM[lP+i];  //在末尾补上对应的被除数位  
  149.         strR[lP] = '\0';    //字符串结束  
  150.     }  
  151.     strR[lP-1] = '\0';      //余数只取前lP-1位(比除数P少一位)  
  152.     strQ[i] = '\0';     //字符串结束  
  153.   
  154.     #if (SHOWPROCESS==1)    //如果需要显示计算过程的话  
  155.         repeat(' ', i);     //先重复打印i个空格进行对齐  
  156.         cout<<strR<<endl;   //打印余数  
  157.     #endif  
  158.   
  159.     delete sM;  //回收空间  
  160. }  
  161.   
  162.   
  163. //该函数输出CRC16的帧检验序列  
  164. //传入待传送的数据strM 帧检验序列保存的空间  
  165. //返回帧检验序列  
  166. char *crc16(const char *strM, char *fcs)  
  167. {  
  168.     char *tmQ = new char[strlen(strM)+1];  
  169.     strm2div(strM, "11000000000000101", tmQ, fcs);  //使用模2计算的方式求出FCS,带传送数据/11000000000000101再取余数  
  170.     return fcs;  
  171. }  
  172.   
  173.   
  174. //模二除法演示  
  175. void div()  
  176. {  
  177.     char Q[1000], R[1000];  
  178.     char M[1000], P[1000];  
  179.     for(;;){  
  180.         cout<<"输入被除数(二进制):";  
  181.         cin>>M;  
  182.         if(M[0]!='0' || M[1]!='\0'){  
  183.             cout<<"输入除数(二进制):";  
  184.             cin>>P;  
  185.             if(P[0]!='0' || P[1]!='\0'){  
  186.                 strm2div(M, P, Q, R);  
  187.                 cout<<M<<'/'<<P<<endl;  
  188.                 cout<<"\t商为:"<<Q<<endl;  
  189.                 cout<<"\t余数:"<<R<<endl<<endl;  
  190.             }  
  191.             else{  
  192.                 break;  
  193.             }  
  194.         }  
  195.         else{  
  196.             break;  
  197.         }  
  198.     }  
  199. }  
  200.   
  201. //crc16校验演示  
  202. void crc()  
  203. {  
  204.     char inbuf[1000], fcs[1000]; //输入缓冲区 FCS缓冲区  
  205.     cout<<"输入M:";  
  206.     cin>>inbuf;  
  207.     while(inbuf[0]!='0' || inbuf[1]!='\0'){ //用户输入M, Ctrl+Break结束程序  
  208.         cout<<"M:"<<inbuf<<endl;  //输出M  
  209.         cout<<"FCS:"<<crc16(inbuf, fcs)<<endl;    //输出CS  
  210.         cout<<"校验帧:"<<inbuf<<fcs<<endl<<endl; //输出加上校验后的发送帧  
  211.         cout<<"输入M:";  
  212.         cin>>inbuf;  
  213.     }  
  214. }  
  215.   
  216.   
  217.   
  218.   
  219. //主函数  
  220.   
  221. int main()  
  222. {  
  223.     //选择  
  224.     char sel = 0;  
  225.     while(sel!='3'){  
  226.         cout<<"1.模二除法"<<endl;  
  227.         cout<<"2.CRC16校验"<<endl;  
  228.         cout<<"3.退出"<<endl;  
  229.         cin>>sel;  
  230.         switch(sel)  
  231.         {  
  232.             case '1':{  
  233.                 div();  
  234.                 break;16  
  235.             }  
  236.             case '2':{  
  237.                 crc();  
  238.                 break;  
  239.             }  
  240.             case '3':{  
  241.                 break;  
  242.             }  
  243.             default:{  
  244.                 cout<<"错误的输入!"<<endl;  
  245.             }  
  246.         }  
  247.     }  
  248.     return 0;  
  249. }  


代码如上,如果你想改成CRC8或者其他的也行,自己修改除数就OK.....


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多