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

C語言實現自動化對拍工具:為競賽程式設計提升測試效率

     編輯:關於C

前言

在演算法競賽與OJ(Online Judge)練習中,「對拍」是驗證程式正確性的關鍵步驟:準備輸入資料,分別運行待測程式與標準程式,比較輸出差異。本文介紹一個基於Linux系統呼叫的C語言自動化對拍器實現,涵蓋檔案重導向、進程控制、輸出比對等核心技術。

一、整體設計思路

  1. 輸入檔案 input.txt,兩個待測可執行檔 main1.exe、main2.exe。
  2. 將標準輸入重導向至 input.txt,標準輸出分別重導向至 stdout1.txt、stdout2.txt。
  3. 調用 system() 執行兩個程式。
  4. 逐行比較兩個輸出檔案,定位首個差異行並顯示內容。

二、關鍵程式碼實現

1. 檔案描述符重導向與程式執行

#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    int fdout1 = open("stdout1.txt", O_RDWR | O_TRUNC | O_CREAT, 0644);
    int fdout2 = open("stdout2.txt", O_RDWR | O_TRUNC | O_CREAT, 0644);
    int fdin   = open("stdin.txt",  O_RDWR, 0644);

    int tempin  = dup(STDIN_FILENO);   // 備份標準輸入
    int tempout = dup(STDOUT_FILENO);  // 備份標準輸出

    char buf1[4096], buf2[4096];

    // --- 執行 main1.exe ---
    dup2(fdin,  STDIN_FILENO);   // stdin  -> input.txt
    dup2(fdout1, STDOUT_FILENO); // stdout -> stdout1.txt
    if (system("./main1.exe") == -1) write(tempout, "NO EXE", 7);

    // --- 執行 main2.exe ---
    fdin = open("stdin.txt", O_RDWR, 0644); // 重新開啟,因標準輸入緩衝區可能已改變
    dup2(fdin, STDIN_FILENO);
    dup2(fdout2, STDOUT_FILENO);            // stdout -> stdout2.txt
    if (system("./main2.exe") == -1) write(tempout, "NO EXE", 7);

    // 恢復標準輸出
    dup2(tempout, STDOUT_FILENO);

    // 重置檔案讀取位置
    lseek(fdout1, 0, SEEK_SET);
    lseek(fdout2, 0, SEEK_SET);
    // ... 後續比較邏輯
}

關鍵點解析:

  • dup()/dup2() 實現檔案描述符複製與重導向,避免系統清除檔案表項。
  • 兩次重導向標準輸入:因 system() 呼叫後,帶緩衝的標準輸入流位置可能改變,需重新 open() 並 dup2() 確保第二個程式讀取完整輸入。
  • lseek() 歸零輸出檔案指針,準備後續 read() 比較。

2. 輸出檔案逐位元組比較


for (;;) {
    int n;
    if ((n = read(fdout1, buf1, 4096)) > 0 && read(fdout2, buf2, 4096) > 0) {
        int i, j = 0;
        char buffer[1024];
        for (i = 0; i < n; i++) {
            buffer[j++] = buf1[i];
            if (buf1[i] == buf2[i]) {
                if (buf1[i] == '\n') { j = 0; line++; }
            } else {
                printf("The difference in line %d between stdout1.txt and stdout2.txt\n", line);
                buffer[j] = '\0'; printf("%s\n", buffer);
                buffer[--j] = buf2[i]; printf("%s\n", buffer);
                break;
            }
        }
        if (i != n) break;
    } else {
        printf("Can't find difference in this instance\n");
        break;
    }
}

逐字元比對,遇換行符計行號。發現差異時印出該行兩版本內容並終止。

三、已知問題與改進方向

  • 緩衝區衝突:標準I/O帶緩衝,read/write 無緩衝,混用導致檔案位置錯位。改進:統一使用 FILE* 操作或 setvbuf() 關閉緩衝。
  • 行長度限制:buffer[1024] 若單行超過1024位元組會溢出。改進:動態分配或分塊處理。
  • 跨平台性:代碼依賴Linux系統呼叫(dup2, fork 隱含於 system),Windows下需改用 CreateProcess + 匿名管道,或直接寫批次檔 .bat 更簡單。
  • 行號準確性:若輸出無換行符或編碼不同,行號可能偏差。

四、總結

這個對拍器雖簡陋,但完整展示了「進程控制 + 檔案重導向 + 輸出比對」的核心流程。對於Linux下C/C++競賽開發者,理解 dup2、system、緩衝區機制極具價值。實際專案建議使用成熟工具(如 diff、Python腳本)或封裝為通用庫。

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