2014年8月10日 星期日

函式呼叫的歸類(C)

在程式語言中,函式呼叫通常可分為兩類,
1.      call by value:可譯為傳值呼叫,呼叫函式時,傳入引數的值會存於暫存變數內,而不使用原本的變數。
2.      call by reference:可譯為傳參考呼叫,呼叫的程序直接使用原本的引數,其值不另行複製。
兩者的差別在於,call by value不會更動到函式外的變數值,而call by reference則會。
在此要先了解一件事,就是"C語言只有call by value",即使傳入的引數是指標或陣列也一樣。這件事在K&RThe C Programming language中已經很清楚的說明了。
但是坊間有些書籍卻把C語言的函式呼叫歸類出call by valuecall by addresscall by reference,也許其意是要使讀者便於理解,但長久以來卻使不少人對此有所誤解。
之所以說C語言只有call by value,是因為函式呼叫時,不論其傳入值如何更改,呼叫方的永遠不會變。
若我們定義函式如下:
type func(type name)
{
        name = .....
}
int main()
{
        type var = value;
        func(var);
        printf("%d",var);
        return 0;
}
不管func對傳入的var做了什麼,main函式裡的值永遠都一樣。
就算傳入陣列,陣列名稱代表的是陣列所在的位址,在函式裡只能對陣列內元素的值做改變,其名稱所存的仍舊相同。所以C語言的函式做不到Call by reference
若傳入指標,指標所存的也是位址,所以變的只是該位址指向的值,位址仍會存於指標之中。
也就是說陣列與指標是將位址當作值來儲存
坊間有些書籍之所以不這麼寫,或許是因為想把傳入陣列和指標與一般變數有所區別,才會把前兩者另外歸類為call by referencecall by address
但實際上,C語言只能說是透過陣列和指標來達成類似這兩種呼叫型式的效果,本質上仍是call by value
關於call by address,我看過三種歸類方式:
1.      call by address歸為call by valuecall by reference之外的第三類。
2.      call by address歸為call by value中的其中一種特例,也就是傳入型態為指標的函式。
3.      call by address等於call by reference
1種我認為是多餘且不正確的做法,因為call by valuecall by reference足以涵蓋所有的呼叫方式,不必再增加一類。
2種可以說得通,畢竟C語言的指標是程式語言中特別的產物,且也沒有違背C語言只有call by value的說法。
3種感覺有些問題,假設C語言把referenceaddress當作一樣的東西看待,那麼這樣的觀點放到C++就不通了,因為C++另外有call by reference的做法。
而且第2種和第3種的call by address本質意義根本就不相同。
所以說,既然call by address沒有統一的說法,不如少用,免得造成誤解。

沒有留言:

張貼留言