校驗和的計算方法

實驗要求

編寫一個計算機程序用來計算一個文件的16位效驗和。最快速的方法是用一個32位的整數來存放這個和。記住要處理進位(例如,超過16位的那些位),把它們加到效驗和中。

要求

1)以命令行形式運行:check_sum infile

其中check_sum爲程序名,infile爲輸入數據文件名。

2)輸出:數據文件的效驗和

附:效驗和(checksum)

參見RFC1071 - Computing the Internet checksum

原理:把要發送的數據看成16比特的二進制整數序列,並計算他們的和。若數據字節長度爲奇數,則在數據尾部補一個字節的0以湊成偶數。

例子:16位效驗和計算,下圖表明一個小的字符串的16位效驗和的計算。

爲了計算效驗和,發送計算機把每對字符當成16位整數處理並計算效驗和。如果效驗和大於16位,那麼把進位一起加到最後的效驗和中。
HelloWorld

思路

這裏計算校驗和的方法是,先把文件中的所有字符都讀成一整個字符串。把每個字符都轉換成十進制的ASCII碼。因爲是把兩個字符合成一個16比特的整數,所以這裏我把高位和高位相加,低位和低位相加,如果字符的個數爲奇數,那麼最後一個字符後面還要補上一個字節的0以湊成偶數。然後處理低位相加的進位和高位相加的進位,這裏要循環處理高位的進位,因爲把高位的進位加到低位上可能還會產生進位。處理的結果還是十進制,轉換成十六進制即可。

如果要以命令行形式運行:check_sum infile。前面的check_sum是程序運行產生的exe可執行文件,後面的infile則是被讀取文件的路徑。另外,程序裏的main函數還要加上參數,int main(int argc, char* argv[]),其中命令行的infile作爲數據傳給argv[1],程序裏用一個變量保存argv[1]作爲路徑。

代碼

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

#define path "test.txt"

// 十進制轉換爲十六進制
string decToHex(int high, int low){
	const std::string hex = "0123456789ABCDEF";
	stringstream ss;
	ss << hex[high >> 4] << hex[high & 0xf];
	ss << hex[low >> 4] << hex[low & 0xf];
	return ss.str();
}

int main(int argc, char* argv[]) {
	string str, tmp = "";
	//path = argv[1];
	ifstream inf(path, ios::in);
	vector<int> l, r;
	while (getline(inf, tmp)) {
		str += tmp;
	}
	cout << str << endl;

	int size = str.size();
	int len = 0;
	cout << "16進制:";
	for (int i = 0; i < size - 1; i += 2) {
		l.push_back((int)str[i]);
		r.push_back((int)str[i + 1]);
		cout << "0x" << decToHex(l[len], r[len]) << " ";
		len++;
	}
	if (size % 2 == 1) {
		l.push_back((int)str[size - 1]);
		r.push_back(0);
		cout << "0x" << decToHex(l[len], r[len]) << " ";
		len++;
	}
	cout << endl;
	// 低位加低位
	int low = 0, t = 0;  // t是進位
	for (int i = 0; i < len; i++) {
		low += r[i];
		if (low > 255) {
			t += (low / 256);
			low %= 256;
		}
	}
	// 高位加高位
	int high = t, t2 = 0;  // t2也是進位
	for (int i = 0; i < len; i++) {
		high += l[i];
		if (high > 255) {
			t2 += (high / 256);
			high %= 256;
		}
	}
	// 處理進位
	while (t2 != 0) {
		low += t2;
		t = 0;
		t2 = 0;
		if (low > 255) {
			t = low / 256;
			low %= 256;
		}
		high += t;
		if (high > 255) {
			t2 = high / 256;
			high %= 256;
		}
	}
	
	cout << "校驗和:" << decToHex(high, low) << endl;
	
	inf.close();
	return 0;
}

Snipaste_2019-12-02_22-03-58
Snipaste_2019-12-02_22-04-38

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章