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】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

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

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

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

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

(0)
上一篇 2023年3月2日 上午5:49
下一篇 2023年3月2日 上午5:49

相关推荐