如何理解signal函数声明
? Signal函數用起來其實很簡單,但是回頭看看他的聲明,相信會有很多人表示費解。自己也在這個問題中糾結了好幾年了,今天終于弄明白,很是興奮,一起分享一下。
? 先看函數原型:void (*signal(int signo, void (*func)(int)))(int);對于看慣了類似unsigned int sleep(unsigned int seconds);這種聲明的人們來說,signal的聲明到底是個啥啊?signal是個函數,后面應該是形參啊,但為什么形參后面又來個形參,我們使用的時候可沒有后面的(int)啊?
? 問題就出在這,難以理解的也是這里。我們又掉進了一個誤區,我們往往以為signal函數的返回值是void類似的,這樣后面的聲明部分就無法理解了。在網上找一些signal的使用方法:?
? if(signal(SIGINT,sig_int)==SIG_ERR)
? ?? ?? ?? ?err_sys("can't catch the SIGINT");
? SIG_ERR長得跟那些信號值好像,如果之前沒看過signal的聲明,那么急躁的人們就會想:signal函數返回的跟信號類型一樣,是一個int型的值。因為往往判錯的時候都只會用到SIG_ERR,記住這樣用倒也不會產生太大的問題。
? 但這樣也就太業余了,根本不利于成長啊。再看看SIG_ERR的定義,它可不是int型的:
???? #define?SIG_ERR?(void(*)())-1
?????#define?SIG_DFL?(void(*)())0
?????#define?SIG_IGN?(void(*)())1
? 然后就必須再弄明白signal函數了。其實聲明最后的那個(int)是用來修飾返回值的,那什么類型的數據需要用形參來修飾呢?自然只有函數指針了。我們把這個聲明修改一下:void (*p)(int);這是什么?它就是一個函數指針啊,該函數指針指向的函數有一個int型的參數。說到這,我們就很容易理解了,signal函數聲明說明了signal函數的返回值是一個函數指針,該函數指向的函數有一個int型的參數。而signal(int signo, void (*func)(int));才是我們在函數里調用signal函數時的使用方法。
? 這里應當注意,signal函數返回的是一個函數指針,而不是一個指針函數。怎么理解呢?函數指針它是個指針,但該指針指向的是一個函數的入口,因此它需要指定參數類型。指針函數是指一個函數它的返回值是指針,普通類型的指針是不存在形參的概念的。將signal函數與char *ctime(const time_t *timep);進行對比。前者返回值是函數指針,因此最后有int來修飾形參,后者返回的是一個char型指針,是一個完整的數據類型,不需要任何修飾。
? 現在應該弄明白了,一個函數聲明由函數返回類型、函數名和形參列表組成,signal函數就是函數返回類型復雜了一點。那能不能讓它表現的更簡單一些呢,最好就是像ctime那樣,一眼就能讓人看到返回值是char*?答案是肯定的。
? Signal函數不是返回的是有一個int型參數、返回值是void型的函數指針嗎,這樣的函數指針的原型(ctime返回值的原型是char*)是什么呢?不是void,而是void(*)(int),這樣的數據類型不好理解,我們可以給它換個簡單的名字,取名字自然就是用typedef了:typedef void (*pSigfunc)(int);(注意這里有分號,typedef是編譯時候處理的,突然發現似乎所有預處理命令后面都沒有分號)當然,也可以給函數取名typedef void (Sigfunc)(int);對應修改后的signal函數聲明可以簡化為pSigfunc signal(int signo, pSigfunc func)或者Sigfunc* signal(int signo, Sigfunc* func);這樣就和直觀的ctime函數一樣了吧!(此處需要對typedef有一定的了解,可以參考我轉的一篇文章《typedef常見用法》)
? 最后看一下signal函數的那幾個返回值。現在應該很容易理解,它們其實就是個強制類型轉換,將一些默認錯誤碼強制轉換為一個函數指針。這個函數指針的原型就是void(*)()了。有人會問,(*)怎么沒有函數名啊?答案也是很簡單地,這是原型不是定義,只有定義時才會有變量。就像int a;int是原型,只有在定義變量時才會用到a(這個問題其實挺弱智的,但我自己一開始也沒弄明白)。然后又有人會問,signal返回的那種函數指針不是有一個int型的形參嗎?這個問題我也糾結了一段時間。之后寫了一段測試代碼(最后給出),才總算弄明白。其實這樣寫更通用一些。
? C語言在聲明一個函數時,如果不指定形參,那么在定義時可以使用任意形參。而C++卻不是這樣,如果定義時的形參個數和聲明時的對不上,那么就會報錯。測試代碼很好地說明了這樣的一個差異,用gcc編譯或者使用g++編譯,兩者的區別是顯而易見的。
? 綜上,C語言其實可以寫的很精練,但過于精練往往帶來的就是不好理解。作為一個熱愛C語言的人來說,她的精練真是讓人又愛又恨,如果有一天,我們能夠完全理解,就能真正欣賞她的美了。
? 最后給出測試代碼:
1 #include <stdio.h> 2 3 typedef void (*func)(/*int*/); 4 5 void print(int a) 6 { 7 printf("%d\n\n", a); 8 } 9 int main() 10 { 11 func f1 = print; 12 f1(10); 13 14 return 1; 15 } test
?
轉載于:https://www.cnblogs.com/wxyy/p/3358880.html
總結
以上是生活随笔為你收集整理的如何理解signal函数声明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: public/private/prote
- 下一篇: exp