- //
-
- /*写在最前面
- 我看了几个CRC16校验的源代码,发现它们都是直接使用数值来进行计算的,那样的话输入不是很方便,你得直接
- 输入八个二进制数对应的十进制数,并且能够校验的只是8*n个二进制数,不过那种有一个好处,计算速度快,并且
- 需要的内存空间也小。
- 我没按照那种方式来进行计算了,我把二进制的表示放到了一个字符串里面,也就是字符串里面的每一位表示一个二进制数,
- 比如二进制的110就用字符串"110"来表示,并且这个CRC16的校验是使用模2除法来弄的。
- 这种方式的有点就是你可以输入的M的长度随便,而且是直接输入01组成的二进制数,当然缺点就是牺牲了效率。
- 写了一个通用的模2除法函数,传入字符串表示的二进制的被除数、除数就能够得到商和余数(CRC16的时候商是没有用的),
- 这个函数可以给你显示出每一步的计算过程,如果你想看看它的计算过程的话,你把下面宏定义的SHOWPROCESS的值改为1就可以 看到,
- 这个函数我没有怎么去验证它是否正确,我自己随便举了几个数据计算,手算和它算是一样的。我用它计算了一下你们课本上的
- 那个,结果是一样的(如果开了显示过程的话,过程也是一样的)。
- 如果你不懂模2除法的计算过程的话你可以把显示计算过程开了(把下面宏定义的SHOWPROCESS的值改为1就可以),多举几个
- 数字进行计算,看看过程就可以弄懂的,显示计算过程也就是为了这。
- 因为没有直接对字符串表示的二进制进行异或的操作,因此就写了一个strxor来实现,它传入异或结果保存的空间和两个操作数就可以
- 得到结果。
- 讲讲什么是异或吧,异或就是相异(不同)的时候为1,相同的时候为0,比如
- 1xor0=1
- 1xor1=0
- 0xor1=1
- oxor0=0
-
- 01010
- xor 10100
- = 11110
-
-
- CRC16得到FCS和原来的M组到一块就是带校验帧的数据,你把这个数据在进行一次CRC16得到的FCS应该为0,这点我检查过多次,是正确的。。。:)
- 是努力的按照你们课本上的意思来实现的了,但是也有可能有错误。。。。。。
-
-
- 哦,提一下,输入的时候你就只输0和1就行,我没有做容错检查,其它的什么非01的字符就别尝试输入了,别为难机器。。。
- 不懂的问我,我今早没课的!
-
- 最后呢,早安、学习快乐!
- */
-
-
- #include <iostream>
- #include <string.h>
- using namespace std;
-
- #define SHOWPROCESS 0 //这个宏定义来控制是否显示模2的计算过程,值为0的时候不显示,值为1的时候显示
-
- //该程序中二进制数用字符串表示,比如二进制的110就用"110"表示
-
-
- //该函数完成二进制数的异或
- //result保存异或的结果,s1和s2为两个二进制串
- char* strxor(char *result, const char *s1, const char *s2)
- {
- int i=0;
- while(s1[i] && s2[i]){
- if(s1[i] != s2[i]){ //相异的时候为1
- result[i] = '1';
- }
- else{ //相同则为0
- result[i] = '0';
- }
- ++i;
- }
- result[i] = '\0'; //字符串结束
- return result;
- }
-
-
- //将字符串左移一位
- //传入字符串本身,返回字符串本身
- char* strlmv(char *s)
- {
- int i=0;
- while(s[i]){
- s[i] = s[i+1]; //前一个等于后一个
- ++i;
- }
- return s;
- }
-
-
- //重复n次打印字符c
- //传入需要重复打印的字符c以及需要重复的次数
- void repeat(char c, int n)
- {
- while(n--){
- cout<<c; //重复打印
- }
- }
-
-
- //该函数完成模2除法
- //传入参数:被除数 除数 保存商的空间 保存余数的空间
- void strm2div(const char *strM, const char *strP, char *strQ, char *strR)
- {
- int lM = strlen(strM); //被除数的长度
- int lP = strlen(strP); //除数的长度
- int L = lM+lP; //被除数和除数的总长
- int i; //循环需要的
-
- char *sM = new char[L+1]; //使用sM替换被除数,前lM个值为除数本身,后lP个值用0补上
-
- for(i=0; i<L; ++i){
- if(i<lM){ //前lM个值为除数本身
- sM[i] = strM[i];
- }
- else{ //后lP个值用0补上
- sM[i] = '0';
- }
- }
- sM[i] = '\0'; //字符串结束
-
- strncpy(strR, sM, lP); //一开始余数照搬被除数
- strR[lP] = '\0'; //字符串结束
-
- #if (SHOWPROCESS==1) //如果需要显示计算过程的话
- cout<<strM<<'/'<<strP<<"的计算过程:"<<endl;
- cout<<sM<<endl; //显示出被除数
- #endif
-
- for(i=0; i<lM; ++i){
- #if (SHOWPROCESS==1) //如果需要显示计算过程的话
- if(i!=0){ //第一次的话不用输出余数(已经除数了被除数了)
- repeat(' ', i); //先重复打印i个空格进行对齐
- cout<<strR<<endl; //打印余数
- }
- #endif
-
- if(strR[0]=='1'){ //如果余数最高位为1
- #if (SHOWPROCESS==1) //如果需要显示计算过程的话
- repeat(' ', i); //先重复打印i个空格进行对齐
- cout<<strP<<endl; //打印除数
- #endif
-
- strxor(strR, strR, strP); //余数与除数做异或,异或后的值直接更新到余数
- strQ[i] = '1'; //商1
- }
- else{ //如果余数高位为0
- #if (SHOWPROCESS==1) //如果需要显示计算过程的话
- repeat(' ', i); //打印i个空格
- repeat('0', lP); //重复lP个0(因为余数高位为0)
- cout<<endl;
- #endif
-
- //这里应该是与lP个0做异或,因为和0做异或等于本身,因此略去
- strQ[i] = '0'; //商0
- }
- strlmv(strR); //把余数左移(最高位丢弃)
- strR[lP-1] = sM[lP+i]; //在末尾补上对应的被除数位
- strR[lP] = '\0'; //字符串结束
- }
- strR[lP-1] = '\0'; //余数只取前lP-1位(比除数P少一位)
- strQ[i] = '\0'; //字符串结束
-
- #if (SHOWPROCESS==1) //如果需要显示计算过程的话
- repeat(' ', i); //先重复打印i个空格进行对齐
- cout<<strR<<endl; //打印余数
- #endif
-
- delete sM; //回收空间
- }
-
-
- //该函数输出CRC16的帧检验序列
- //传入待传送的数据strM 帧检验序列保存的空间
- //返回帧检验序列
- char *crc16(const char *strM, char *fcs)
- {
- char *tmQ = new char[strlen(strM)+1];
- strm2div(strM, "11000000000000101", tmQ, fcs); //使用模2计算的方式求出FCS,带传送数据/11000000000000101再取余数
- return fcs;
- }
-
-
- //模二除法演示
- void div()
- {
- char Q[1000], R[1000];
- char M[1000], P[1000];
- for(;;){
- cout<<"输入被除数(二进制):";
- cin>>M;
- if(M[0]!='0' || M[1]!='\0'){
- cout<<"输入除数(二进制):";
- cin>>P;
- if(P[0]!='0' || P[1]!='\0'){
- strm2div(M, P, Q, R);
- cout<<M<<'/'<<P<<endl;
- cout<<"\t商为:"<<Q<<endl;
- cout<<"\t余数:"<<R<<endl<<endl;
- }
- else{
- break;
- }
- }
- else{
- break;
- }
- }
- }
-
- //crc16校验演示
- void crc()
- {
- char inbuf[1000], fcs[1000]; //输入缓冲区 FCS缓冲区
- cout<<"输入M:";
- cin>>inbuf;
- while(inbuf[0]!='0' || inbuf[1]!='\0'){ //用户输入M, Ctrl+Break结束程序
- cout<<"M:"<<inbuf<<endl; //输出M
- cout<<"FCS:"<<crc16(inbuf, fcs)<<endl; //输出CS
- cout<<"校验帧:"<<inbuf<<fcs<<endl<<endl; //输出加上校验后的发送帧
- cout<<"输入M:";
- cin>>inbuf;
- }
- }
-
-
-
-
- //主函数
-
- int main()
- {
- //选择
- char sel = 0;
- while(sel!='3'){
- cout<<"1.模二除法"<<endl;
- cout<<"2.CRC16校验"<<endl;
- cout<<"3.退出"<<endl;
- cin>>sel;
- switch(sel)
- {
- case '1':{
- div();
- break;16
- }
- case '2':{
- crc();
- break;
- }
- case '3':{
- break;
- }
- default:{
- cout<<"错误的输入!"<<endl;
- }
- }
- }
- return 0;
- }
代码如上,如果你想改成CRC8或者其他的也行,自己修改除数就OK.....
|