C++ 实现校验和计算(无取反步骤)

题目

编写一个计算机程序用来计算一个文件的16位效验和。最快速的方法是用一个32位的整数来存放这个和。记住要处理进位(例如,超过16位的那些位),把它们加到效验和中。

  • 要求:
    1. 以命令行形式运行:check_sum infile。其中check_sum为程序名,infile为输入数据文件名。
    2. 输出:数据文件的效验和
  • 附:效验和(checksum)
    - 原理:把要发送的数据看成16比特的二进制整数序列,并计算他们的和。若数据字节长度为奇数,则在数据尾部补一个字节的0以凑成偶数。
    - 例子:16位效验和计算,下图表明一个小的字符串的16位效验和的计算。为了计算效验和,发送计算机把每对字符当成16位整数处理并计算效验和。如果效验和大于16位,那么把进位一起加到最后的效验和中。

C++ 实现校验和计算(无取反步骤)

本地数据样式

C++ 实现校验和计算(无取反步骤)

分析

  1. 这道题的校验和没有要求最后取反,实际上求和后是要取反的;
  2. 原理不难理解,就是数据转换成十六进制,然后十六进制求和。四位十六进制,所以也要求进位加到结果中;
  3. 难点在于字符转十六进制,十六进制有进位相加(我这里是用string存储十六进制数,可能网上还有更直接的十六进制的存储方式和计算方式);
  4. 先用char类型数组把数据逐个存进数组中;
  5. 将每两个char字符转为四位十六进制,其中会先将每个char字符先转为二位十六进制;
  6. 最后进行十六进制的求和,我没有选择将进位留到最后再相加,而是每一次运算都完成进位的相加,因为经过多次运算后,不能确定进位的位数。

程序流程图

C++ 实现校验和计算(无取反步骤)

代码

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;

//命令行输入
void waitInput(string command, string &infile) {
	cout << "Please input check_sum infile, infile is the file name!" << endl;
	cin >> command >> infile;
	while (command != "check_sum") {
		cout << "Wrong command! Please reenter!" << endl;
		cin >> command >> infile;
	}
	cout << endl;
}

//一个字符转二位十六进制
string CToH(char charIndex) {
	//char强制转换为int
	int temp = charIndex;
	//十六进制的一二位(现在是十进制)
	int first = temp / 16;
	int second = temp % 16;
	//十进制转十六进制(用srting存)
	string res;
	string resFirst;
	string resSecond;
	if (first < 10) resFirst.append(to_string(first));
	if (second < 10) resSecond.append(to_string(second));
	if (first >= 10) {
		switch (first) {
		case 10:	resFirst.append("A"); break;
		case 11:	resFirst.append("B"); break;
		case 12:	resFirst.append("C"); break;
		case 13:	resFirst.append("D"); break;
		case 14:	resFirst.append("E"); break;
		case 15:	resFirst.append("F"); break;
		}
	}
	if (second >= 10) {
		switch (second) {
		case 10:	resSecond.append("A"); break;
		case 11:	resSecond.append("B"); break;
		case 12:	resSecond.append("C"); break;
		case 13:	resSecond.append("D"); break;
		case 14:	resSecond.append("E"); break;
		case 15:	resSecond.append("F"); break;
		}
	}
	res.append(resFirst);
	res.append(resSecond);
	return res;
}

//每对字符转为四位十六进制
string makePairChar(char firstChar, char secondChar) {
	//两string相加即可
	return CToH(firstChar) + CToH(secondChar);
}

//四位十六进制相加
void sum(string &first, string second) {
	//进位
	int carryInt = 0;
	for (int i = 3; i >= 0; i--) {
		//先将计算的该位转为十进制
		int firstInt;
		int secondInt;
		int res;
		if(first[i] <= '9') firstInt = (int)first[i] - '0';
		else firstInt = (int)first[i] - 55;
		if (second[i] <= '9') secondInt = (int)second[i] - '0';
		else secondInt = (int)second[i] - 55;
		//获得十进制结果
		res = firstInt + secondInt + carryInt;
		//进位归零
		carryInt = 0;
		//结果转换为char,存进string
		if (res < 10) first[i] = res + '0';
		else if (res >= 10 && res <= 15) first[i] = 'A' + res - 10;
		else {
			if (res > 15 && res < 26) first[i] = res - 16 + '0';
			else first[i] = 'A' + res - 26;
			carryInt = 1;
		}
	}
	//若四位都运算完成后,有第五位的进位,则继续和进位运算,消除进位
	if (carryInt) {
		string carry = "0001";
		sum(first, carry);
	}
}

int main() {
	//等待命令行输入
	string infile, command;
	waitInput(command, infile);
	
	//打开文件
	ifstream dataFile(infile);
	if (!dataFile.is_open()) {
		cout << "dataFile文件打开失败!" << endl;
		return 1;
	}

	//将文件所有字符存进数组
	//最后一个字符为-1,不存进数组
	cout << "文件数据:" << endl;
	vector<char> dataArray;
	while (!dataFile.eof()){
		char str = dataFile.get();
		cout << str;
		if ((int)str == -1) continue;
		dataArray.push_back(str);
	}
	cout << endl << endl;
	//用完关闭
	dataFile.close();

	//把每对字符当成16位整数处理
	//用string数组存每对字符的16进制数
	vector<string> pairChar;
	//判断奇数个字符还是偶数个字符
	int remainder = dataArray.size() % 2;
	//若是奇数个,循环走到倒数第二个
	//若是偶数个,循环走到倒数第一个
	for (unsigned  int i = 0; i < dataArray.size() - remainder; i += 2) {
		string pairCharIndex = makePairChar(dataArray[i], dataArray[i + 1]);
		pairChar.push_back(pairCharIndex);
	}

	//若数据字节长度为奇数,则在数据尾部补一个字节的0以凑成偶数
        //一字节0也就是空字符,空字符就是
	if (remainder) {
		string pairCharIndex = makePairChar(dataArray[dataArray.size() - 1], '');
		pairChar.push_back(pairCharIndex);
	}

	//计算校验和
	string res = pairChar[0];
	for (unsigned  int i = 1; i < pairChar.size(); i++) sum(res, pairChar[i]);

	//打印结果
	cout << "校验和:" << endl;
	cout << res << endl;

	return 0;
}

结果截图

  • 数据为例子(答案相同)
    C++ 实现校验和计算(无取反步骤)

  • 数据增加一行
    C++ 实现校验和计算(无取反步骤)

原文链接: https://www.cnblogs.com/wasi-991017/p/12923309.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++ 实现校验和计算(无取反步骤)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/197610

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午7:37
下一篇 2023年2月12日 下午7:37

相关推荐