「Hello, World!」是幾乎所有程式設計師寫的第一行程式碼。但如果不使用任何可讀的字元、不呼叫 printf 或 puts,甚至完全隱藏主函式,還能印出這行字串嗎?本文收集六種極具創意、甚至略帶「變態」風格的 C 語言 Hello World 實作,展示前置處理器、指標運算、goto、位元操作等特性的極限應用。這些寫法雖不適合實務專案,卻能深化對 C 語言編譯機制的理解。
#define _________ }
#define ________ putchar
#define _______ main
#define _(a) ________(a);
#define ______ _______(){
#define __ ______ _(0x48)_(0x65)_(0x6C)_(0x6C)
#define ___ _(0x6F)_(0x2C)_(0x20)_(0x77)_(0x6F)
#define ____ _(0x72)_(0x6C)_(0x64)_(0x21)
#define _____ __ ___ ____ _________
#include <stdio.h>
_____
解析: 所有關鍵字、函式名、括號、甚至主函式主體全被巨集重新定義。_____ 展開後完整生成一個呼叫 putchar 印出每個 ASCII 碼(0x48='H', 0x65='e'...)的 main() 函式。展示前置處理器進行文字替換的圖靈完備性。
#include <stdio.h>
main(){
int x=0, y[14], *z=&y;
*(z++)=0x48; *(z++)=y[x++]+0x1D; *(z++)=y[x++]+0x07;
*(z++)=y[x++]+0x00; *(z++)=y[x++]+0x03; *(z++)=y[x++]-0x43;
*(z++)=y[x++]-0x0C; *(z++)=y[x++]+0x57; *(z++)=y[x++]-0x08;
*(z++)=y[x++]+0x03; *(z++)=y[x++]-0x06; *(z++)=y[x++]-0x08;
*(z++)=y[x++]-0x43; *(z++)=y[x]-0x21;
x=*(--z);
while(y[x]!=NULL) putchar(y[x++]);
}
解析: 利用陣列 y 當作緩衝區,z 為指標依序寫入。第一個字元直接寫 'H'(0x48),後續字元皆以前一個字元為基準加減偏移量計算而得(例如 'e' = 'H' + 0x1D)。最後倒著遍歷陣列輸出。展示指標遞增、陣列索引運算與 ASCII 碼數學關係的巧妙結合。
#include <stdio.h>
#define __(a) goto a;
#define ___(a) putchar(a);
#define _(a,b) ___(a) __(b);
main() {
_:__(t) a:_('r',g) b:_('$',p) c:_('l',f) d:_(' ',s) e:_('a',s)
f:_('o',q) g:_('l',h) h:_('d',n) i:_('e',w) j:_('e',x) k:_(' ',z)
l:_('H',l) m:_('X',i) n:_('!',k) o:_('H',o) p:_('e',m) q:_('l',n)
r:_('l',c) s:_('o',d) t:_(' ',b) u:_('w',a) v:_('o',u) w:_('r',v)
x:_('l',w) y:_('d',x) z:_('!',y)
}
解析: 完全放棄迴圈與函式呼叫,改用大量 goto 標籤跳轉。每個標籤印出一個字元並跳往下一個標籤,形成一條長長的執行鏈。字元順序被打亂分散在各標籤中,靠跳轉順序重組出 "Hello world!"。極致展示 goto 的流程控制能力(以及為什麼現代軟體工程極力避免它)。
#include <stdio.h>
main(int argc, char *argv[]) {
static char *s = "Hello, World!\n";
if (*s) putchar(*s++), main(0, 0);
}
解析: 利用靜態字串指標 s 保持狀態,每次遞迴印出一個字元並遞增指標。當遇到字串結束符 \0 時遞迴終止。展示 C 語言允許 main 遞迴呼叫(雖然 C++ 標準禁止),以及靜態區域變數跨呼叫保持值的特性。
#include <stdio.h>
main(){int i=0;while(puts("Hello, World!")&~i++);}
解析: puts 回傳非負值(成功),~i++ 最初為 ~0(全 1),按位元 AND 結果為真,迴圈繼續;i 變 1 後 ~1 最低位為 0,配合 puts 回傳值導致條件為假,迴圈恰好執行一次。展示位元運算子與短路求值的巧妙組合。
#include <stdio.h>
main(){printf("%s","Hello, World!\n"+0);}
解析: 看似平凡,實則利用字串字面常量在記憶體中連續分布的特性,+0 無實質運算但強調指標算術。若改為 +1 則輸出 "ello, World!\n",展示字串指標偏移的基本觀念。
這六種寫法橫跨前置處理器元程式設計、指標算術、非結構化流程控制、遞迴、位元運算、指標偏移等核心議題。它們提醒我們:
若您有更瘋狂的 Hello World 寫法,歡迎分享交流!