[题目大意]
你在一家拥有很名个人计算机的公司上班。你的老板,Penny Pincher博士,想要把这些个人计算机联网,但是他又不想花钱买网卡。你无意中告诉了老板每台计算机出厂时就带有一个异步串行端口,老板当然把脑防动到这个不用花钱的解决方案上。于是指派你完成编写通信软件的任务,以实现计算机之间联网。
你阅读了许事美手通信的书籍,知道在传送及接收信息时容易产生错误。解决间题的典型的方法是,在信息的术尾附加错误校验信息。该信息允许接收程序校验传送的信息是否有错误产生(在大多数情况下)。于是,你跑到图书馆借了一本厚厚的关于通信的书利用周末(当然没有加班费)研究情误校验方法。
最后,你决定CRC(Cyclic Redundancy Check)是最适合的错误校验方案.井向PennyPincher博土详细描述了该错误校验方案.
将待传递的信息看作是“ 串很长的二进制数。信息的第个字 节(Byte)是这个二进制数的最高有效字节,第二个字节是第二个最高有效字节,依此类推。把这个二进制数称为“m".传送信息时,会在“m”之后加上2个字节的CRC校验码,整个二进制数称为“m2”.
选择CRC校验码的方法:当"m2”除以某个16位的值"g”时,余数为0.这样就使接收程序比较容易判断信息是否产生了传送错误。所以对接收到的任何信息除以“g”.如果余数为0即代表此信息正确。
注意,大部分书中都建议“g”的值为奇数.你决定用34943作为“g”的值
输入
必须设计一个算法,对所有传送的信息计算CRC的值。为了测试算法的正确性,编写一个程序读取数据(每行都是字符,不包括行结束符)。对每一行信息,计算相应的CRC值.并输出该CRC值(十六进制).占一行。对每行输人,不会超过1024个ASCII字符。当- .行的第一列是#时,代表输人结束。
输出
对每组测试数据输出行,是以十六进制表示的CRC值。注意:CRC的取值范围应该是0到34942(十进制)之间。
样例输入
this is a test
A
#
样例输出
77 FD
00 00
0C 86
【程序代码】
#include<stdio.h>
#define Generator 34943
int main()
{
unsigned char c, flag;
int count;//一行中的字符数
//CRC数据结构
union
{
unsigned int L;
struct
{
unsigned char b1;
unsigned char b2;
unsigned char b3;
unsigned char b4;
}CRC;
}data;
while (1)
{
count = 0;
//计算一行所有的字符,除以Generator的余数
data.L = 0;
while (scanf("%c", &c) &&c!= '\n')
{
count++;
flag = c;
//采用每个字符取模的方法(将计算结果移到高位,后面两个字节存放CRC)
data.L = ((data.L << 8) + c) % Generator;
}
//将发送信息的余数,移到整数最高和次高字节
data.L = (data.L << 16) % Generator;
if (data.L != 0)data.L = Generator - data.L;
if (count == 1 && flag == '#')break;
printf("%02X %02X\n", (int)data.CRC.b2, (int)data.CRC.b1);
}
return 0;
}
L(联合体) | |||
b4 | b3 | b2(CRC高位字节) | b1(CRC低位字节) |
知识点总结:
移位运算符
"<<" 左移运算符:将左侧运算符的二进制位按右侧制定的数值进行移位,移位的方向是向左移动,每移动一位,原左侧的二进制位自动丢弃,低位补零(相当于原来的数被乘以2);
">>"右移运算符:该操作符当操作数向右移位,最右侧的位被丢弃,左侧最高位补0.(相当于将原来的数除以2);