※ 本文轉寄自 ptt.cc, 文章原始頁面
看板YOLO
作者okcool
標題

Fw: [問卦] 為甚麼C語言自訂函式一定要在主程式上面?

時間
留言281則留言,249人參與討論
推噓237 ( 237044 )
※ [本文轉錄自 Gossiping 看板 #1SzydGFl ] 作者: jserv (松鼠) 看板: Gossiping 標題: Re: [問卦] 為甚麼C語言自訂函式一定要在主程式上面? 時間: Wed Jun 5 21:55:19 2019 ※ 引述《fragmentwing (片翼碎夢)》之銘言: : 如題 : 最近終於開始自學C語言 : 為甚麼C語言一定至少要放個原型在主程式上方才行? : 或者說,明明都是一行一行讀取,其他語言是怎麼做到可以把函式到處亂擺的 這問題非常好,我不知為何會引來負面聲音,可能是原發問人沒有把「其他語言」清楚 標示出來吧?抑或是問題太簡短呢?有趣的問題如果被忽略,那真是太可惜。 其實由 Dennis M. Ritchie (以下簡稱 dmr) 開發的早期 C 語言編譯器 [1] 沒有明確 要求 function prototype 的順序。dmr 在 1972 年發展的早期 C 編譯器,原始程式碼 後來被整理在名為 "last1120c" 磁帶中 [2],我們如果仔細看 c00.c 這檔案,可發現 位於第 269 行的 mapch(c) 函式定義,在沒有 forward declaration [3] 的狀況下, 就分別於第 246 行和第 261 行呼叫,奇怪吧? 而且只要再瀏覽 last1120c 裡頭其他 C 語言程式後,就會發現根本沒有 #include 或 #define 這一類 C preprocessor [4] 所支援的語法,那到底怎麼編譯呢?在回答這問題 前,摘錄 Wikipedia 頁面的訊息: > As the C preprocessor can be invoked separately from the compiler with > which it is supplied, it can be used separately, on different languages. > Notable examples include its use in the now-deprecated imake system and for > preprocessing Fortran. 原來 C preprocessor 以獨立程式的形式存在,所以當我們用 gcc 或 cl (Microsoft 開發工具裡頭的 C 編譯器) 編譯給定的 C 程式時,會呼叫 cpp (伴隨在 gcc 專案的 C preprocessor) 一類的程式,先行展開巨集 (macro) 或施加條件編譯等操作,再來 才會出動真正的 C 語言編譯器 (在 gcc 中叫做 cc1)。值得注意的是,1972-1973 年 間被稱為 "Very early C compilers" 的實作中,不存在 C preprocessor (!),當時 dmr 等人簡稱 C compiler 為 "cc",此慣例被沿用至今,而無論原始程式碼有幾個檔 案,在編譯前,先用 cat [5] 一類的工具,將檔案串接為單一檔案,再來執行 "cc" 以便輸出對應的組合語言,之後就可透過 assembler (組譯器,在 UNIX 稱為 "as") 轉換為目標碼,搭配 linker (在 UNIX 稱為 "ld") 則輸出執行擋。 所以說,在早期的 C 語言編譯器,強制規範 function prototype 及函式宣告的順序 是完全沒有必要的,要到 1974 年 C preprocessor 才正式出現在世人面前,儘管當時 的實作仍相當陽春,可參見 dmr 撰寫的 "The Development of the C Language" [6] C 語言的標準化是另一段漫長的旅程,來自 Bell Labs 的火種,透過 UNIX 來到研究 機構和公司行號,持續影響著你我所處的資訊社會。 你或許會好奇,function prototype 的規範有什麼好處呢?這就要從 "Rationale for International Standard -- Programming Languages -- C" [7] 閱讀起,依據 C9X RATIONALE 的第 70 頁 (PDF 檔案對應於第 78 頁),提到以下的解說範例: extern int compare(const char *string1, const char *string2); void func2(int x) { char *str1, *str2; // ... x = compare(str1, str2); // ... } 編譯器裡頭的最佳化階段 (optimizer) 可從 function prototype 得知,傳遞給函式 compare 的兩個指標型態參數,由於明確標注了 "const" 修飾子,所以僅有記憶體地 址的使用並讀取相對應的內容,但不會因為修改指標所指向的記憶體內容,從而沒有產生 副作用 (side effect)。這樣編譯器可有更大的最佳化空間,可對照「你所不知道的 C 語言:編譯器和最佳化原理篇」,得知相關最佳化手法。 一如 C9X RATIONALE 提到,C 語言和其他受 Algol 影響的程式語言,都具備 function prototype 機制,這使得編譯時期,就能進行有效的錯誤分析和偵測。無論是 C 語言、 B 語言,還是 Pascal 語言,都可追溯到 ALGOL 60 [9]。 ALGOL 是Algorithmic Language (演算法使用的語言) 的縮寫,提出巢狀 (nested) 結構 和一系列程式流程控制,今日我們熟知的 if-else 語法,就在 ALGOL 60 出現。 ALGOL 60 和 COBOL 程式語言並列史上最早工業標準化的程式語言。 可參見本看板 #1SdKXN4t 程式語言的演化,深受底層工具和硬體限制的影響,這次探討的 function prototype 及函式宣告的順序,其實就反映出編譯器演化的歷程。人類史上第一個編譯器,A-0 System 開發於 1951-52 年間,注意到當時的用語是 "System",而且名稱 A-0 代表 Arithmetic Language version 0,與其說是今天我們提及的高階語言編譯器,不如說是 程式的載入器 (loader) 或連結器 (linker)。 相關訊息可參見本看板 #1RhWSNPG 黑格爾在其 1820 年的著作「法哲學原理」提到: (德語原文) > Was vernuftig ist, das ist wirklich; > und was wirklich ist, das ist vernuftig. 英語可解讀為 "What is rational is actual and what is actual is rational.", 像是 C 語言這樣的工業標準,至今仍活躍地演化,當我們回顧發展軌跡時,凡是合乎 理性 (vernuftig),也就必然會出現、或成為現實 (wirklich),反過來說也成立。 甚至我們可推敲 C9X RATIONALE 字裡行間,每個看似死板規則的背後,其實都可追溯出 像是上方的討論。 歡迎關注「你所不知道的 C 語言」系列講座: https://hackmd.io/@sysprog/HJpiYaZfl 千萬別忘了 C 語言的發展就是為了開發 UNIX 作業系統和相關系統程式,而 Linux 核心 自然就是將 UNIX 精神發揚光大的智慧結晶,歡迎關注「Linux 核心設計」課程,附有 線上教材: http://wiki.csie.ncku.edu.tw/linux/schedule [1] Very early C compilers and language, https://www.bell-labs.com/usr/dmr/www/primevalC.html [2] 位於 GitHub 的副本, https://github.com/mortdeus/legacy-cc/ [3] https://en.wikipedia.org/wiki/Forward_declaration [4] https://en.wikipedia.org/wiki/C_preprocessor [5] cat 工具程式的作用是 "concatenate and print file", https://www.unix.com/man-page/posix/1posix/cat/ [6] The Development of the C Language, https://www.bell-labs.com/usr/dmr/www/chist.html [7] Rationale for International Standard -- Programming Languages -- C http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf [8] 你所不知道的 C 語言:編譯器和最佳化原理篇, https://hackmd.io/@sysprog/Hy72937Me [9] Algol 60, https://en.wikipedia.org/wiki/ALGOL_60 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.116.82.61 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1559742928.A.3EF.html

281 則留言

XXXXHAY, 1F

Costco5566, 2F
hello world

sujianwei20, 3F
前十

moswu, 4F
我也這麼覺得

jiajia1, 5F
快來推ㄍ不然被當文組

Ericz7000, 6F
前十

he00504616, 7F
先推

angerD, 8F
先推

siamese, 9F
這不是基本的嗎

a22918097, 10F

VXcc, 11F
嗯嗯嗯 就是這樣

ggBird, 12F

fox875566, 13F
看不懂

Cybershit, 14F
大大安安推一個

Friend5566, 15F
推一下 免得被說看不懂

redDest, 16F

landysh, 17F

lturtsamuel, 18F
看到這篇好像我不是CS的一樣QQ

rewrite404, 19F
朝聖

g5637128, 20F
跪著推

pzyc79, 21F
這就是為什麼我恨C

gungunme5566, 22F
專業

brian1015, 23F

Mesa5566, 24F
116一定是廢文 幫補血

obdv, 25F
淦 這樣摸不到C罩拉

barry910543, 26F
大神又出來普渡眾生了

HowieH, 27F
看不懂還是要推

NTULioner, 28F
嗯嗯 我也是這樣想的

Turas, 29F
CCC

OGCOGCOGCOGC, 30F
看不懂

TrevorStory, 31F

salesperson, 32F
恩恩跟我想的一樣 只是我懶的打

cjamhe01385, 33F
每次線上講座必看,可惜在新竹上班,不然就去旁聽了

ymx3xc, 34F
我也是這麼想的

compuworld, 35F
朝聖推

hizuki, 36F
講古

WYchuang, 37F
老闆問我為什麼跪著上班

jackyT, 38F
這個釣到jserv太扯

FlynnZhang, 39F

usoko, 269F
只有寫過C-- 嗚嗚嗚嗚嗚

ms0007912, 270F
不知到但感覺很屌

ohlong, 271F
你資工系?

EthereumPTT, 272F
有神快拜

HowLeeHi, 273F
推,Linker取名ld,所以Linker和Loader是有淵源的吧?

HowLeeHi, 274F
譬如說在link及load階段,都會做linking和relocation

jserv, 275F
@HowLeeHi, 不僅有淵源,早期根本就是一體的 :-)

jserv, 276F
可參照「你所不知道的 C 語言」系列講座,有兩項linker相關

jserv, 277F
@balcony5566, 一定是你的記事本軟體不好用,在此誠心建議

jserv, 278F
改用有媽祖加持的編輯器Mazu Editor!

jserv, 279F

gipo776, 280F
先跪

ikenaka, 281F
老師我愛你
※ 轉錄者: okcool (125.230.18.220 臺灣), 06/08/2019 23:34:45