// 第一届顶嵌杯决赛 B题
//7913377 vrs570540852 3754 Accepted 376K 0MS GCC 2259B 2010-11-23 01:05:35
//这是一道模拟Modbus协议的题目,主要考察C底层编程 涉及网络传输数据编码,CRC校验码,浮点数转换
//其中浮点数转换中,我直接在内存中写上该编码(以unsigned long方式),然后用float指针读这块内存,自动让其转换为浮点数
//题目中的提示:你可以根据IEEE754标准自行设计转换算法;或者直接利用C语言float类型的实现特性:x86 linux下,
// gcc编译器将C语言代码“float f = 34.9;”编译成汇编代码“movl $0x420b999a, -4(%ebp)” (AT&T x86汇编格式),
// 也就是说,单精度浮点数34.9在内存中就是由整数0x420b999a来表示的,你可以利用这一特性来完成转换。
#include<stdio.h>
#define dataStart 6
unsigned int CRC;
char inputStr[100];
//字符转为16进制整数
unsigned int ChangeTo16(char ch)
{
if(ch-'9'<=0)
return ch-'0';
else
return ch-'A'+10;
}
//一轮CRC转化
void CRC_Change(unsigned int data)
{
int i;
CRC^=data;
for(i=0;i<8;i++)
{
if(CRC&0x0001)
{
CRC>>=1;
CRC^=0xA001;
}
else
CRC>>=1;
}
}
int main()
{
unsigned int slaAddr,func,staAddr,numOfbyte;
unsigned int temp,tempCRC;
unsigned int i,len;
unsigned long floatData;
unsigned long *longAddr;
float *floatAddr;
while(scanf("%u,%u,%u,%u",&slaAddr,&func,&staAddr,&numOfbyte)!=EOF)
{
CRC=0xFFFF;
CRC_Change(slaAddr);
CRC_Change(func);
CRC_Change(staAddr>>8);
CRC_Change(staAddr&0x00ff);
CRC_Change(numOfbyte>>8);
CRC_Change(numOfbyte&0x00ff);
temp=CRC&0x00ff;
temp<<=8;
CRC=(CRC>>8)|temp;
printf("%02X%02X%04X%04X%X\n",slaAddr,func,staAddr,numOfbyte,CRC);
scanf("%s",&inputStr);
CRC=0xFFFF;
CRC_Change(ChangeTo16(inputStr[0])*16+ChangeTo16(inputStr[1]));
CRC_Change(ChangeTo16(inputStr[2])*16+ChangeTo16(inputStr[3]));
len=ChangeTo16(inputStr[4])*16+ChangeTo16(inputStr[5]);
CRC_Change(len);
for(i=0;i<len*2;i+=2)
CRC_Change(ChangeTo16(inputStr[i+dataStart])*16+ChangeTo16(inputStr[i+1+dataStart]));
temp=CRC&0x00ff;
temp<<=8;
CRC=(CRC>>8)|temp;
tempCRC=ChangeTo16(inputStr[i+dataStart])*0x1000
+ChangeTo16(inputStr[i+1+dataStart])*0x0100
+ChangeTo16(inputStr[i+2+dataStart])*0x0010
+ChangeTo16(inputStr[i+3+dataStart]);
if(CRC!=tempCRC)
{
printf("CRC_ERROR\n");
continue;
}
for(i=0;i<len*2;i+=8)
{
floatData=ChangeTo16(inputStr[i+dataStart])*0x10000000
+ChangeTo16(inputStr[i+1+dataStart])*0x01000000
+ChangeTo16(inputStr[i+2+dataStart])*0x00100000
+ChangeTo16(inputStr[i+3+dataStart])*0x00010000
+ChangeTo16(inputStr[i+4+dataStart])*0x00001000
+ChangeTo16(inputStr[i+5+dataStart])*0x00000100
+ChangeTo16(inputStr[i+6+dataStart])*0x00000010
+ChangeTo16(inputStr[i+7+dataStart]);
longAddr=&floatData;
floatAddr=(float*)longAddr; //这一步相当危险,要注意慎重!
if(i>0)
printf(",");
printf("%.1f",*floatAddr);
}
printf("\n");
}
return 0;
}