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