C Type Defination to English

PL 教授給的 8 頁 Func Ptr 閱讀材料
那就來玩一下吧。
wait to refer:rule



The flip side of this is that you have to deal with old mistakes and with compatibility problems. For example, I consider the C declarator syntax an experiment that failed.-Bjarne Stroustrup, in his SlashDot interview on 2/25/2000.

我嘗試寫成 Haskell 的定義型態。
那個 Type* 能理解就好了 (逃

https://cdecl.org/

  1. long *a(int)

    1
    declare a as function (int) returning pointer to long
    1
    a :: Int -> Long*
  2. long (*b(int))

    1
    declare b as function (int) returning pointer to long
    1
    b :: Int -> Long*
  3. long (*c)(int)

    1
    declare c as pointer to function (int) returning long
    1
    c :: (Int -> Long)*
  4. long *d(int)(char)

    1
    declare d as function (int) returning function (char) returning pointer to long
    1
    d :: Int -> (Char -> Long*)
  5. long (*e(int))(char)

    1
    declare e as function (int) returning pointer to function (char) returning long
    1
    e :: Int -> (Char -> Long)*
  6. long (*f)(int)(char)

    1
    declare f as pointer to function (int) returning function (char) returning long
    1
    f :: (Int -> (Char -> Long))*
  7. void qsort(void *, size_t, size_t,int (*)(const void *, const void *))

    1
    2
    3
    4
    5
    6
    7
    declare qsort as function (pointer to void,
    size_t,
    size_t,
    pointer to function (pointer to const void,
    pointer to const void)
    )
    returning int) returning void
    1
    qsort :: Void* -> Size_t -> Size_t -> (Void* -> Void*)* -> Void
  8. start with the identifier

  9. look to the right for brackets[ ] or parentheses()
  10. look to the left for asterisks
  11. remember that parentheses group
  12. finally, look at the type (eg. int)

reference link

重點是先往右讀,然後讀到括號,再往左讀,如此往復。
先找變數宣告名稱,\w+ 後跟的是 ( ,則此宣告為一函數,否則為變數。

先往右,遇到 (,為函數,參數為 fnArg。
往左讀,遇到 *,回傳為一指標,指向 long。
long *fn(fnArg) -> fn :: FnArg -> Long*

如果再右邊還有括號,則他的回傳指標為函數指標,其參數為該括號內容。
long *fn(fnArg)(argOfAfnRtnedByAFn) -> fn :: FnArg -> (ArgOfAfnRtnedByAFn -> Long)*

如果後面一直有括號,其指的函數類型就一直向右 eval 括號就好了。
long *fn(fnArg)(argOfAfnRtnedByAFn)(argOfAfnRtnedByAFnRtnedByAFn)
-> fn :: FnArg -> (ArgOfAfnRtnedByAFn -> (ArgOfAfnRtnedByAFnRtnedByAFn -> Long*))

注意指標可能出現的位置。
long (*fn(fnArg)(argOfAfnRtnedByAFn))(argOfAfnRtnedByAFnRtnedByAFn)
-> fn :: fnArg -> (ArgOfAfnRtnedByAFn -> (ArgOfAfnRtnedByAFnRtnedByAFn -> Long)*)

long (*fn(fnArg))(argOfAfnRtnedByAFn)(argOfAfnRtnedByAFnRtnedByAFn)
-> fn :: fnArg -> (ArgOfAfnRtnedByAFn -> (ArgOfAfnRtnedByAFnRtnedByAFn -> Long))*

有時指標不只一個,看著辦吧。

Illegal combinations include:
- cannot have an array of functions
()() - cannot have a function that returns a function
()[] - cannot have a function that returns an array

所以其實上面五項,應該只有幾個是 Illegal 的(from reference)

其實回傳函數指標和回傳函數在 C 裡是一樣的事情

變數名前有*代表他是一個指標,
long *ptr -> ptr :: Long*

如果右邊有閉括號,代表他是一個函數指標。
long (*ptr)(argOfApointedFn) -> ptr :: (ArgOfApointedFn -> Long)*

其指的函數類型就一直向右 eval 括號就好了。
long (*ptr)(argOfApointedFn)(argOfAFnRtnedByAFnPointedByAPtr)
-> ptr :: (ArgOfApointedFn -> (ArgOfAFnRtnedByAFnPointedByAPtr -> Long))*

一樣,有時指標不只一個,看著辦吧。

我都快搞不清我在寫啥了(
Haskell 的 Type 表達比較好理解(

------------- EOF -------------