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

Quine 程式設計:讓 C 程式輸出自身原始碼

     編輯:關於C語言

什麼是 Quine?

Quine(以邏輯學家 Willard Van Orman Quine 命名)是一種「不接受任何輸入、輸出自身完整原始碼」的程式。這是一種經典的程式設計智力遊戲,也是對語言特性(字串處理、轉義、格式化輸出)掌握程度的絕佳測試。

極簡版 Quine(單行)

#include <stdio.h>
main(){char *s="#include<stdio.h>%cmain(){char *s=%c%s%c;printf(s,10,34,s,34);}";printf(s,10,34,s,34);}

核心技巧:

  • %c 對應 ASCII 碼:10 = 換行符 \n,34 = 雙引號 "。
  • 字串 s 同時作為「資料」與「格式化模板」,printf 將自身內容填入模板並輸出。

可讀性較佳版本(含縮排)

#include <stdio.h>

main() {
    char *s = "#include<stdio.h>%cmain(){%c%cchar *s=%c%s%c;%c%cprintf(s,10,10,9,34,s,34,10,9,10);%c}";
    printf(s, 10, 10, 9, 34, s, 34, 10, 9, 10);
}
  • 10 = \n,9 = \t,34 = "。
  • 模板字串中預留 %c 位置,依序填入換行、縮排、引號、字串本體。

帶版權聲明的完整版

//Copyright (c) LeafCore
#include <stdio.h>

void main() {
    char *s = "//Copyright (c) LeafCore%c#include<stdio.h>%cvoid main() {%c%cchar *s=%c%s%c;%c%cprintf(s,10,10,10,9,34,s,34,10,9,10);%c}";
    printf(s, 10, 10, 10, 9, 34, s, 34, 10, 9, 10);
}

進階:可執行檔產生自身原始碼檔案

//Copyright (c) LeafCore
#include <stdio.h>

main() {
    FILE *fp = fopen("file.c", "w");
    char *s = "//Copyright (c) LeafCore%c#include<stdio.h>%cmain(){%c%cFILE *fp=fopen(%cfile.c%c,%cw%c);%c%cchar *s=%c%s%c;%c%cfprintf(fp,s,10,10,10,9,34,34,34,34,10,9,34,s,34,10,9,10,9,10,9,10);%c%cfclose(fp);%c%creturn 0;%c}";
    fprintf(fp, s, 10, 10, 10, 9, 34, 34, 34, 34, 10, 9, 34, s, 34, 10, 9, 10, 9, 10, 9, 10);
    fclose(fp);
    return 0;
}

編譯執行後,會在當前目錄生成 file.c,內容即為程式自身完整原始碼。這展示了「自我複製」程式的基本原理,也是病毒、編譯器引導、元程式設計的理論基石之一。

關鍵點總結

  1. 字串自指:字串變數同時包含「程式碼骨架」與「自身內容佔位符」。
  2. 轉義處理:利用 printf("%c", 34) 輸出雙引號,printf("%c", 10) 輸出換行,避免原始碼中直接寫死特殊字元導致巢狀引號混亂。
  3. 格式化參數順序:嚴格對應模板中 %c/%s 的位置,任何參數錯位都會導致輸出錯誤。

延伸思考

Quine 的構造思想可推廣至:

  • 多語言 Quine(Polyglot Quine):同一份原始碼在多種語言下均為 Quine。
  • 輸出自身變體(如輸出經修改的自身),構成「程式演化」模型。
  • 應用於編譯器自舉、程式混淆、程式碼完整性驗證等領域。

嘗試手寫一個 Quine,是深入理解程式語言「資料即程式、程式即資料」本質的最佳練習。

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