signal函式宣告的理解

2021-06-21 20:33:03 字數 2246 閱讀 2968

先看函式原型: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語言的人來說,她的精練真是讓人又愛又恨,如果有一天,我們能夠完全理解,就能真正欣賞她的美了。

理解函式宣告 signal函式的宣告

分兩步分析 假定變數fp是乙個函式指標,呼叫方法如下 fp 因為fp是乙個函式指標,那麼 fp就是該指標指向的函式,所以 fp 就是呼叫該函式的方式。ansi c標準允許程式設計師將上式簡寫為fp 的運算子高於 2.使用具體的函式指標替換fp,此處將0做型別強制轉換,轉換為函式指標,替換fp。對乙個...

如何理解signal函式宣告

signal函式用起來其實很簡單,但是回頭看看他的宣告,相信會有很多人表示費解。自己也在這個問題中糾結了好幾年了,今天終於弄明白,很是興奮,一起分享一下。先看函式原型 void signal int signo,void func int int 對於看慣了類似unsigned int sleep ...

簡單理解函式宣告 以signal函式為例

signal 幾乎所有c語言程式的實現過程中都要用到signal函式,作為捕獲不同步的一種方式。我們使用者要呼叫signal函式,可以這樣使用,首先在標頭檔案中加入 include,然後我們可以這樣呼叫signal函式 signal signal type,sighandler t hander 這...