如何理解signal函式宣告

2021-06-21 10:37:03 字數 2471 閱讀 4554

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

最後給出測試**:

#include typedef void (*func)(/*int*/);

void print(int a)

int main()

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

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

signal函式宣告的理解

先看函式原型 void signal int signo,void func int int 對於看慣了類似unsigned int sleep unsigned int seconds 這種宣告的人們來說,signal的宣告到底是個啥啊?signal是個函式,後面應該是形參啊,但為什麼形參後面又來...

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

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