在演算法競賽與OJ(Online Judge)練習中,「對拍」是驗證程式正確性的關鍵步驟:準備輸入資料,分別運行待測程式與標準程式,比較輸出差異。本文介紹一個基於Linux系統呼叫的C語言自動化對拍器實現,涵蓋檔案重導向、進程控制、輸出比對等核心技術。
input.txt,兩個待測可執行檔 main1.exe、main2.exe。input.txt,標準輸出分別重導向至 stdout1.txt、stdout2.txt。system() 執行兩個程式。#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() 比較。
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;
}
}
逐字元比對,遇換行符計行號。發現差異時印出該行兩版本內容並終止。
read/write 無緩衝,混用導致檔案位置錯位。改進:統一使用 FILE* 操作或 setvbuf() 關閉緩衝。buffer[1024] 若單行超過1024位元組會溢出。改進:動態分配或分塊處理。dup2, fork 隱含於 system),Windows下需改用 CreateProcess + 匿名管道,或直接寫批次檔 .bat 更簡單。這個對拍器雖簡陋,但完整展示了「進程控制 + 檔案重導向 + 輸出比對」的核心流程。對於Linux下C/C++競賽開發者,理解 dup2、system、緩衝區機制極具價值。實際專案建議使用成熟工具(如 diff、Python腳本)或封裝為通用庫。