首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 代碼統計工具:註釋行、有效代碼行、混合行、函數個數

     編輯:C++ 入門

需求背景

專案中需統計 C++ 源文件的:
1. 註釋行數(含純註釋、代碼+註釋混合行)
2. 有效代碼行數(含純代碼、混合行)
3. 代碼註釋公共行數(同一行既有代碼又有註釋)
4. 函數個數(以最外層 `{}` 為標誌)

難點分析

  • 雙引號內容屏蔽:字符串字面量中的 `//`、`/* */`、`{` `}` 不應被識別。
  • 單引號屏蔽:字符字面量如 `'{'` 可能干擾大括號計數。
  • 註釋嵌套/優先級:`//` 在 `/* */` 內失效;`/* */` 在 `//` 內失效;字符串內均失效。
  • 多行註釋跨行:需維持跨行狀態標記。
  • 轉義字符:`\"`、`\'`、`\\` 不結束字符串/字符。

算法設計:單遍歷狀態機

逐行讀入,逐字符掃描,維護狀態標記:
- `bSyh`:雙引號內(字符串字面量)
- `bXgx`:多行註釋 `/* */` 內
- `bHs`:大括號嵌套層數(-1 表示頂層)
- `bCode`:本行已遇到有效代碼
- `bZs`:本行已遇到註釋

處理邏輯

  1. 跳過行首空白字符(空格、制表、換行、回車)。
  2. 空行判斷:非多行註釋狀態下遇到行尾 `\0` → 空行計數++。
  3. 字符循環:
    a. 雙引號切換 `bSyh`(處理轉義 `\"`)。內部字符直接跳過。
    b. 單引號跳過 3 字符(`'x'` 形式),處理轉義。
    c. 若在多行註釋 `bXgx` 中:檢測 `*/` 結束,否則繼續。行尾按混合/純註釋計數。
    d. 檢測 `//`:若非多行註釋中,按混合/純註釋計數,**直接結束本行掃描**。
    e. 檢測 `/*`:啟動 `bXgx`,標記註釋,跳過 `/*`。
    f. 行尾 `\0`:根據 `bCode`/`bZs` 更新行計數。
    g. 有效代碼字符:`bCode=1`;檢測 `{` `}` 更新 `bHs`,`bHs` 從 0 降到 -1 時函數計數++。

完整代碼

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

int main() {
    string line;
    ifstream ifs("Test.cpp");
    if (!ifs) { cout << "文件打開失敗" << endl; return 0; }

    int bSyh = 0, bXgx = 0, bHs = -1, bCode = 0, bZs = 0;
    int nKh = 0, nZs = 0, nDm = 0, nGg = 0, nHs = 0;

    while (!ifs.eof()) {
        int i = 0;
        getline(ifs, line);
        bCode = 0; bZs = 0;
        if (bXgx) bZs = 1; // 跨行註釋繼續

        while (i < line.size() && (line[i]==' '||line[i]=='\t'||line[i]=='\r'||line[i]=='\n')) i++;
        if (!bXgx && i == line.size()) { nKh++; continue; } // 空行

        while (true) {
            // 雙引號處理
            if (!bSyh && line[i] == '\"' && (i==0 || line[i-1] != '\\')) { bSyh = 1; i++; continue; }
            if (bSyh) {
                if (line[i] == '\"' && (i==0 || line[i-1] != '\\')) bSyh = 0;
                else if (i == line.size()) { if(bZs)nZs++; if(bCode)nDm++; if(bZs&&bCode)nGg++; break; }
                i++; continue;
            }
            // 單引號跳過
            if (line[i] == '\'' && (i==0 || line[i-1] != '\\')) { i += 3; continue; }
            // // 註釋
            if (!bXgx && line[i] == '/' && i+1 < line.size() && line[i+1] == '/') {
                if (bCode) { nZs++; nDm++; nGg++; } else { nZs++; }
                break;
            }
            // /* 開始
            if (!bXgx && line[i] == '/' && i+1 < line.size() && line[i+1] == '*') {
                i += 2; bXgx = 1; bZs = 1; continue;
            }
            // 多行註釋中
            if (bXgx) {
                if (line[i] == '*' && i+1 < line.size() && line[i+1] == '/') { i++; bXgx = 0; }
                else if (i == line.size()) { if(bCode){nDm++;nZs++;nGg++;}else{nZs++;} break; }
                i++; continue;
            }
            // 行尾
            if (i == line.size()) { if(bZs)nZs++; if(bCode)nDm++; if(bZs&&bCode)nGg++; break; }
            // 有效代碼
            if (line[i] == '{') bHs++;
            else if (line[i] == '}') { if (bHs == 0) nHs++; bHs--; }
            i++; bCode = 1;
        }
    }

    cout << "註釋: " << nZs << endl;
    cout << "代碼: " << nDm << endl;
    cout << "空行: " << nKh << endl;
    cout << "公共: " << nGg << endl;
    cout << "函數: " << nHs << endl;
    return 0;
}

已知局限

  • 類、結構體、命名空間、全局數組初始化等頂層 `{}` 會被誤計為函數。需結合關鍵字上下文進一步過濾。
  • 宏定義、模板、預處理指令未處理。
  • 極端註釋情況(如 `/* // */`)邏輯以優先級為準。

總結

通過狀態機單遍歷實現精確統計,核心在於字符串/字符屏蔽、註釋優先級、跨行狀態維護、行級計數延遲到行尾。代碼可作為代碼分析工具的基礎模塊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved