CRC16校验 模二除法

//

/*写在最前面
我看了几个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.....


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RobinTang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值