前言
我們都知道,寫完了的C代碼是需要編譯鏈接之後才能運行的(也許你不需要手動點擊編譯,但是IDE可能幫你做了這件事),那麼能不能讓C代碼像執行shell腳本或者Python腳本一樣,直接可運行呢?類似於:
$ ./main.c
就可以直接運行了。
看起來雖然沒啥用,但是感覺有點小刺激。
小試牛刀
對於文本內容,系統首先會嘗試當成shell進行解釋執行,這一點還不明白的朋友,建議先閱讀《爲什麼執行命令開頭需要./》。
不過話又說回來,.c最終要編譯成可執行文件,如果想要它直接執行,那麼就得悄悄地在這個過程中做點小動作了。我們試試把編譯過程加進去:
#!/usr/bin/gcc -o main "$0" && ./main
//main.c 公衆號編程珠璣
#include<stdio.h>
int main(void)
{
printf("hello,編程珠璣\n");
return 0;
}
試一下:
$ ./main.c
./main.c:1:2: error: invalid preprocessing directive #!
#!/usr/bin/gcc -o main "$0" && ./main
誒,報錯了,看起來像是GCC編譯main.c的時候報錯了。
仔細一想,這不太正常了嗎?很明顯第一行就不是C代碼的合法內容啊!
再接再厲
怎麼辦呢?能不能把第一行既能夠執行編譯,又能夠變成合法的C代碼內容呢?
這不很簡單嗎?註釋不就是這樣的內容嗎?
//usr/bin/gcc -o main "$0" && ./main
//main.c 公衆號編程珠璣
#include<stdio.h>
int main(void)
{
printf("hello,編程珠璣\n");
return 0;
}
嗯?還真是巧了,對於C代碼來說,第一行是註釋,對於shell來說,也是一個正常的路徑。再試一下:
$ ./main.c
./main.c: line 2: //main.c: No such file or directory
./main.c: line 4: syntax error near unexpected token `('
./main.c: line 4: `int main(void)'
咦?怎麼還是報錯了?前面說到,這裏的內容必須既能被shell識別,又能是合法C代碼,顯然第二行不符合啊。
投機取巧
很明顯,除了第二行,後面的第三行,第四行都不能被當成shell正常執行。那麼就果斷一點好了,執行完了第一行咱就退出還不行嗎?
於是,第一行變成下面這樣:
//usr/bin/gcc -o main "$0" && ./main ;exit
再來執行一下
$ ./main.c
hello,編程珠璣
實際上就達到了下面的效果:
$ gcc -o main main.c && ./main
還能更通用嗎?
有人就問了,這裏指定了生成文件名,而且如果程序還帶了參數怎麼辦?
但是用//開頭已經很取巧了。別忘了,C裏面還有終極註釋大法:
#if 0
#endif
而且巧的是,#也是shell腳本的註釋符。這就有趣了。
我們改造如下:
#if 0
proName="${0%.*}" #去掉文件名後綴,作爲程序名
gcc -o $proName "$0"
./$proName "$@" #傳入命令行參數
rm $proName
exit
#endif
//main.c 公衆號編程珠璣
#include<stdio.h>
int main(void)
{
printf("hello,編程珠璣\n");
return 0;
}
現在再來看,是不是符合要求了:
-
文件名不限定
-
支持程序傳入命令行參數
有人又要問了,如果多文件程序怎麼辦?
還能怎麼辦?makefile,cmake bazel等用起來。
總結
好了,祕密也被你知道了,現在一點都不神奇了吧!這裏純屬娛樂,僅供學習其中的原理,對於編譯鏈接成可執行程序,構建工具是一個好的選擇。
相關精彩推薦
關注公衆號【編程珠璣】,獲取更多Linux/C/C++/數據結構與算法/計算機基礎/工具等原創技術文章。後臺免費獲取經典電子書和視頻資源