神奇,C代碼竟然能當成shell腳本一樣“直接”執行!

 

 

前言

我們都知道,寫完了的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++/數據結構與算法/計算機基礎/工具等原創技術文章。後臺免費獲取經典電子書和視頻資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章