分析一下下面一小段代碼的輸出。
#include <stdio.h>#include <stdlib.h>void main(int j){ printf("%d\n", j); ((void(*)(int))((int)&main + ((int)&exit - (int)&main) * (j / 1000)))(j + 1);}
主要是printf後的一段程式不太易讀,我們不妨將它拆開來看,首先void(*)(int)是一個函數指標的強制類型轉換,可以用#define代替。而&main是main函數的入口地址,&exit是exit的入口地址,前面加上(int)將其強制轉換成int類型,故而這一句的前面部分是一個函數調用,而後面的(j + 1)則是一個傳入的函數實參。改寫後的程式如下所示。
#include <stdio.h>#include <stdlib.h>#define FUNC void(*)(int)void main(int j){int m = (int)&main;int e = (int)&exit;printf("%d\n", j);((FUNC)(m + (e - m) * (j / 1000)))(j + 1);}
改寫說明:&main可以在int m = (int)&main;的聲明後用m代替,&exit可以在int e = (int)&exit;的聲明後用e代替,這兩個一個是入口地址,一個是出口地址。而(FUNC)是將
(m + (e - m) * (j / 1000))
部分強制轉換為函數指標指向的函數類型,後面的j + 1為參數。若這一部分取值為&main,則又返回main執行,且參數為j + 1;若取值為&exit,則退出。
注意到一般的main函數中可接受3個參數,為int argc, char *argv[], char *env[]這3個參數。而直接編譯運行此段程式時沒有任何其它命令輸入,對應的argc即為j在此處值為1,則此處最開始j/1000為0,上面的(m + (e - m) * (j / 1000))的值即為m,則為&main,故而又返回main執行,且參數為j + 1,即2。如此依次遞增,到j為1000時,該部分的值為e,即為&exit,則退出程式。整段程式的輸出即為遞增地依次輸出1到1000,然後退出。
注意若非直接編譯運行,而選擇在命令列中運行,假設該程式產生test.exe,在cmd中輸入[test.exe所在路徑]\test.exe [任意參數] [任意參數],則j的初始值為3,再加多一個[任意參數]則j初始為4,這跟main函數的接受參數相關。