巴倫西亞語翻譯
式子(3) 實際是界說一個體名 IamFunc , 它是一個傳回值為整數且需要二個整數參數的函數 .
式子(4) 和式子(3) 對照, 只是回傳值由 int 變為 int* . 因為在 IamFunc 右側的函數呼喚運算子 () 翻譯社 比在左側的取值運算子 * 翻譯社 優先官僚來得較高.
式子(5) 和式子(3) 對照, 多加了括號強制取值運算子 * 先履行, 所以函數 釀成了指向函數的指標 , (名為 IamFunc 的資料型態, 是一個指標指向一個傳回值為整數且需要二個整數參數的函數 ).
有人說 式子(3) 和式子(5) 是對等的, 關於這點我不是很清晰, 需要多一點時候找資料及 作些實行來驗證.
謎底也對也錯: 就 typedef 的界說內容來講: 他們是不一樣的. 然則就後續程式的現實運用來講: 這二個 typedef 界說完全一致, 程式的寫法溝通翻譯社 結果也完全一樣. 之所以會有這類情形, 是因為 C 編譯器對 function pointer 的界說和處置懲罰體式格局和其他指標其實不一樣, 並且還有點另類: function pointer 的取址運算 & 及取值運算 * 後果或有分歧 (一個是指標的位址, 一個是函數的位址) 但是只要一帶上 () 效果都是呼喚函數並且不會搞錯 (好奇異喔!). 這裡有一篇有關 function pointer 的申明 (英文) Declaring翻譯社 Assigning, and Using Function Pointers 是 Usenet 上 comp.lang.c FAQ list 的保護人 Steve Summit 師長教師寫的, 對於 function pointer 的取址運算 & 及取值運算 * 有明白的解說, 供應給各人參考.
typedef uint8_t Buffer[16];
Buffer xBuf;
xBuf[0] = 3;
xBuf[1] = 2;
第3行有些小小的奇異, 定義變數時似乎沒有指定是陣列, 後面卻可以用陣列的寫法. 其實第3行相當於 uint8_t xBuf[16]
用法可能看起來有點奇異, 卻可以包管每次用 Buffer 界說或宣佈的陣列變數 必然是 16 個 uint8_t 元素. 益處是陣列的巨細需要改變時翻譯社 只要修改 typedef 不必全部專案翻找一遍, 還要擔憂是否是有改漏了.
如果碰到看不懂時, 建議你可以把界說中的 typedef 拿掉, 同時資料型態名稱換成變數的名稱翻譯社 就會比力輕易理解. 例如: 把 typedef uint8_t Buffer[16]; 去掉 typedef 翻譯社 Buffer 換成變數名 xBuf , 釀成 uint8_t xBuf[16];
下面的例子含有例舉 (enum) 別號定義, 應該不消多作诠釋.
typedef unsigned char bool;
typedef struct _list_node_ {
unsigned long size;
strcut _list_node_ *next;
} LIST_NODE;
bool flag1, flag2;
LIST_NODE node0, *free_list;
第1行的 typedef 為 unsigned char 取了個好記的別號 bool .
第2~5行則將構造 _list_node_ 擴充為資料型態並為其定名為 LIST_NODE . 這裡要注意的是佈局內部有一個指標指向和本身一樣的結構. 在 typedef 的定義中天成翻譯公司 們只能利用 struct _list_node_ * 而不成以利用 typedef 的成果 LIST_NODE (因為 LIST_NODE 還沒有界說完成. 翻譯公司也能夠把 typedef 的界說和結構的定義拆開來).
第7~8行則拿新定義的別號翻譯社 來界說本來程式要定義的變數. 如果再把 1~5 行的 typedef 移到標頭檔 (xxx.h), 只留下 7~8 行這二行變數界說的部分, 程式看起來就簡練多了.
上面有關 LIST_NODE 的部份, 也可以換一個寫法:
typedef struct _list_node_ {
unsigned long size;
strcut _list_node_ *next;
} LIST_NODE, *pLIST_NODE;
LIST_NODE node0;
pLIST_NODE free_list;
這個 typedef 寫法用了一個一般比較不經常使用的 翻譯社 . 其實就是和 int32_t a翻譯社 *p; (註三) 界說了 "一個 32 位元整數變數 a 和一個指到 32 位元整數的指標變數 p " 一樣, 如許的寫法界說了一個佈局 _list_node_ 的別號 LIST_NODE , 和一個指標型的別名 pLIST_NODE . 所以本例和上例這二種寫法界說出來的變數 node0 翻譯社 free_list 成果是完全一致的.
註三: 利用 , 將多個變數的界說/宣告連結起來時, 要注意 * (指標) 其實不算在配合的資料型態這一邊, 而是算在變數名稱這一邊. 所以上面的例子裡的 int32_t a, *p; 和 int32_t *p, a; 和 int32_t* p翻譯社 a; 意義上都是一樣的. 初學者需要特別小心最後一種寫法, 非常輕易讓人弄錯搞含混了.
// Examples of typedef a pointer
typedef struct _list_node_ * pLIST_NODE; // (1)
typedef struct _list_node_ (* pLIST_NODE); // (2)
// Examples of typedef a function or pointer of function
typedef int IamFunc (int翻譯社 int); // (3)
typedef int *IamFunc (int翻譯社 int); // (4)
typedef int (*IamFunc)(int, int); // (5)
式子(1) 是利用了卻構指標翻譯社 寫法很平居, 看起來應當很習慣.
式子(2) 的寫法看起來感受似乎有點玄機... 但其實並沒有, 式子(1)和(2)這二個寫法是一樣的:
在界說或宣佈指標 int * ptr 的寫法中, 星號左右雙方的空白是無關緊要的翻譯社 所以 int* ptr , int *ptr , int * ptr , int*ptr 翻譯社 都是准確的並且意義也溝通.
而註釋上你可以說 ptr 是一個 int* , 也能夠說 *ptr 是一個 int . 所以多加了括號其實不會改變它的意義.
註二: ANSI C 標準文件說: 會實際佔據記憶體空間的宣佈 稱為界說 . 所以 ANSI C 說的宣佈 包含了界說 及純宣佈 . 而註一及以下本文中所指的宣佈 則是指沒有 佔據記憶體空間的純宣告 翻譯社 而不是 ANSI C 原先所指的宣告 , 特此申明. 請參考維基網站 Declaration (computer programming) 段落二 'Declaration vs. definition' 及段落三 'Declarations and Definitions')
轉換化簡
例一: 變數為一陣列, 陣列元素內容為 函數指標
typedef int (*MathFunc)(float翻譯社 int);
int do_math(float arg1, int arg2) {
return arg2;
}
int call_a_func(MathFunc call_this) {
int output = call_this(5.5, 7);
return output;
}
int final_result = call_a_func(&do_math);
再來一個更極真個例子 (也是借用自 Wiki 網站對 typedef 的解說)
// 原始寫法:
void (*b[10])(void (*)());
// 轉換為:
typedef void (*pFunParam)(); // 右半部, 函數的參數
typedef void (*pFunx)(pFunParam); // 左半部的函數
pFunx b[10];
例三: 變數為指向陣列之指標, 陣列元素固定為 9, 陣列元素內容為 函數指標
int do_math(float arg1, int arg2) {
return arg2;
}
int call_a_func(int (*call_this)(float, int)) {
int output = call_this(5.5翻譯社 7);
return output;
}
int final_result = call_a_func(&do_math);
套用 typedef 以後, typedef 本身易讀並且 call_a_func 的參數部份翻譯社 也變得簡單易讀.
雜記
習慣上, C 說話 (如: standard C library, POSIX) 會在衍生性型別號的後面加上 _t翻譯社 像是 size_t .
定義或宣佈變數時, 新設的型別不行以和 signed , unsigned 一路適用 (即使是 原始型別是 int 翻譯社 short 翻譯社 long ... 之類的型別). 來由很簡單 signed int 和 unsigned int 是劃分的根基資料型態, 意即 signed 和 unsigned 這二個 keyword 並非 int 的 storage class 或是 qualifier 之類的潤色 keyword.
// 下行的語法是錯誤: static 不行以出現在 typedef 中
typedef static int newINT;
newINT x翻譯社 y, x;
// 要改成以下二行才行 (static 必須移到變數界說式)
typedef int newINT;
static newINT x翻譯社 y, z;
別的二個限制詞 (qualifier, const 和 volatile ) 則沒有上述的限制: 可以出現在新資料型態的 typedef 界說中; 也可以不呈現在新資料型態的 typedef 定義中翻譯社 而改在變數界說或宣告時加上限制. 當然, 我們弗成以二者都加. 同時, 要當心變數定義或宣佈內容包括有指標 的情形, 此時 keyword const 和 volatile 的限制標的釀成有二個: 一個是指標自己 另外一個是指標所指向的資料 . 這個時刻到底誰被 keyword 限制, 取決於 keyword 呈現的位置 .
下面的式子(1), 式子(2)和式子(3)寫法相通翻譯社 是界說一個指標變數 指向常數資料 (指標值可變, 資料值不行變).
式子(4)和式子(5)寫法相通翻譯社 是界說一個常數指標 指向可更動的資料 (指標值不行變, 資料值可變).
式子(1)的寫法經常會被誤以為應該和式子(5)相等 翻譯社 所以就毛病的把式子(1)化簡為式子(5). 但現實上是式子(1)應該以化簡為式子(3). (我們應當把式子(5) const ptr p 中的 ptr 當作和 const int x 中的 int 一樣, 是一個資料型態. 而不要把它以 typedef 的定義 char * 來替換.)
// define a non-const pointer to const data
const char * p; // (1)
char const * p; // (2)
typedef const char * ptr; // (3-1)
ptr p; // (3-2)
// define a const pointer to non-const data
char * const p; // (4)
typedef char* ptr; // (5-1)
const ptr p; // (5-2)
備註:
式子(4)和式子(5-2)在現實運用中是不 OK 的, 因為 (指標變數的) 變數值自己是一常數, 必須在界說 變數的同時指定其常數值. 現實利用的例子如下: 式子(4a)是指定某一個變數的位址; 式子(4b)是指定一特定位址.
char * const p = &x; // (4a)
char * const p = 0x200000; // (4b)
不外式子(4b)的用法會多浪費一個指標變數的空間 (即變數 p 自己). 這是因為 0x200000 本身就是一個 const , 所以沒需要用變數來儲存它然後又宣佈說該變數是常數不可以更動. 其實我們可以直接用 type casting 的方式把 0x200000 轉型就可以了, 即 ((char *)0x200000) . 若是覺得後續利用它的程式敘述會欠好讀翻譯社 那可以插手 #define CONST_P ((char *)0x200000) 這樣的置換巨集, 然後把程式論述改成使用 CONST_P 來取代 ((char *)0x200000) 即可.
式子(1), 式子(2)和式子(3)在現實應用中是 OK 的翻譯社 同時它只是限定弗成以經由指標變數 p 來改變其所指到的變數翻譯社 而不是限制所指到的變數必需是常數.
typedef const char * ptr;
ptr p;
char x = 0x20;
p = &x;
*p = 0x21; // Compiler will alert.
x = 0x21; // OK
最常看到的毛病典範榜樣是天成翻譯公司 們想要寫一個像 strcmp() 那樣的函數, 於是宣佈了以下的函數原型 mystrcmp(const char *翻譯社 const char *) , 然後為了想簡化於是又增添了界說 typedef char * pstr; 接著把函數原型宣佈改成 mystrcmp(const pstr, const pstr) 翻譯社 然後就掛掉了... (我們進展的是字串比力時不要去動到字串的內容, 而不是指標值不克不及更動)
圈套 -- 有關 storage class 和 qualifier 常常泛起的毛病
由於 typedef 的功效 會被視為資料型態 的擴充, 界說或宣告變數時可使用指定儲區種別 (storage class) 的四個 keyword (auto , static 翻譯社 extern , register ) 來加以潤色, 因此 typedef 的內容自己是不可以利用這四個 keyword 的.
C 說話中 typedef 可以用來擴充 C 原本的資料型態. 通常天成翻譯公司 們會將某個資料型態或者將經常使用的資料型態組合 賜與一個比力直觀而易懂的別號. 定義別號以後我們就能夠像利用原有的資料型態 來宣佈或界說變數一樣翻譯社 直接拿它來宣佈或界說(註一, 註二) 變數.
接著, 我們進一步加一些變化
enum color { black, white, gold, pink };
typedef enum color iPhoneColor;
iPhoneColor x = gold;
再下來是陣列 array 的例子:
unsigned char flag1, flag2;
struct _list_node_ {
unsigned long size;
strcut _list_node_ *next;
} node0, *free_list;
再來看的是改用 typedef 後的模樣:
底下的程式片斷是變數界說的部份翻譯社 沒有利用 typedef 的模樣:
// Wrong definition:
typedef char * pstr;
mystrcmp(const pstr, const pstr);
// Correct definition:
typedef const char * cpstr;
mystrcmp(cpstr, cpstr);
// 原始寫法:
int *(*a[5])(int, char*);
// 轉換1:
typedef int *(*pFun)(int, char*);
pFun a[5];
// 轉換2:
typedef int *Func(int翻譯社 char*);
Func *a[5];
轉換1: 在 *a[5] 中, [] 優先權比 * 高, 故把 a[5] 留在本來變數界說的式子, 其餘的轉為 typedef
轉換2: 把 *a[5] 全部留在原來的變數界說式翻譯社 其餘的轉為 typedef
例二: 變數為一陣列, 陣列元素內容為 函數指標翻譯社 函數之參數為 函數指標
參考
en.wikipedia.org typedef
blog.sina.com.cn typedef的四个用處和两大圈套
pixnet.net/blog C 說話:輕鬆讀懂複雜的定義 (Define and Read the complex declarations)
Declaring翻譯社 Assigning, and Using Function Pointers
// 原始寫法:
doube(*)() (*e)[9];
// 轉換為:
typedef double (*pFuny)(); // 左半部
typedef pFuny (*pFunParamy)[9]; // 右半部
pFunParamy e;
函數指標最常見的利用是使用在 callback 的手藝上. 由於需要將某一函數的位址當成參數傳送給另外一個函數翻譯社 因此利用 typedef 替這種 callback 函數的指標界說一個新名字 (新資料型態), 可以大幅提昇程式的可讀性, 日後保護及修改上比力不會犯錯.
下面的例子借用自 Wiki 網站對 typedef 的解說
轉換化簡的原則:
不克不及破壞原有之運算前後次序.
轉換化簡沒有固定的謎底, 完全視程式的需要取 typedef 的截斷點.
void (*signal(int sig, void (*func)(int)))(int);
// 轉換成下面的樣子
typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t func);
C
C 說話
typedef
function pointer
struct pointer
pointers
指標
結構指標
函數指標
註一: 宣告 和界說 有所分歧. 界說變數 會實際佔據記憶體空間, 而宣告變數 則只產生參考的保持翻譯社 稍後貫穿連接程式時再保持到在其他模組界說的變數. 我們一般把宣告變數 擺放在 header file (.h 檔) 中, 有需要的模組或程式只要 include 便可. 而界說變數 則視情況放在主程式或相幹的模組中翻譯社 固然它平常也會 include 該 header file.
再來看一些用 typedef 轉換化簡的例子: from blog.sina.com.cn typedef的四个用處和两大圈套
感覺很費勁看不下去了嗎? 先讀一下這一篇 C 說話:輕鬆讀懂複雜的定義 (Define and Read the complex declarations)
轉換化簡程序:
先取一個適合的截斷點
將截斷點之後的低優先權運算以 typedef 界說為別號
然後用別號界說或宣佈截斷點之前的高優先權運算.
本篇文章引用自此: http://magicjackting.pixnet.net/blog/post/65865174-c-%e8%aa%9e%e8%a8%80%3atypedef-%e7%9a%84%e7%94%a8 有關各國語文翻譯公證的問題歡迎諮詢天成翻譯公司02-77260931
anthonjhrb3aa 發表在 痞客邦 留言 (0) 人氣( )
留言列表