2010-01-07 161 views
6

你能施放此類型的函數指針:你可以將一個指向一種類型的函數的指針轉換爲另一種類型的函數嗎?

void (*one)(int a) 

這種類型之一:

void (*two)(int a, int b) 

,然後安全地調用指向的與額外的參數(S)擁有的功能被投了?我曾認爲這樣的事情是非法的,兩種功能類型必須兼容。 (意思是相同的原型 - 同樣的返回值,同樣的參數列表。)但是,這正是的GTK +代碼這一點似乎是在做(從here拍攝):如果你看到了「點擊

g_signal_connect_swapped(G_OBJECT(button), "clicked", 
         G_CALLBACK(gtk_widget_destroy), G_OBJECT(window)); 

「信號(或者只是看看從第一環節其使用的其他的例子),你會看到它的處理程序,預計聲明如下:

void user_function(GtkButton *button, gpointer user_data); 

當你通過函數g_signal_connect_swapped註冊處理程序()時,小部件指針和數據指針參數按順序交換,因此聲明應該看起來像這樣:

void user_function(gpointer user_data, GtkButton *button); 

這是問題所在。註冊爲回調gtk_widget_destroy()函數的原型是這樣的:

void gtk_widget_destroy(GtkWidget *widget); 

只取一個參數。據推測,這是因爲數據指針(一個GtkWindow)和指針到信令微件(一個的GtkButton)被交換時,它接收將是窗口指針唯一的參數,並且按鈕指針,這將在以後通過,將靜默被忽略。一些谷歌搜索已經出現了類似的例子,甚至像gtk_main_quit()這樣的函數的註冊根本沒有任何參數。

我是在相信這是一個標準的違反正確嗎? GTK +開發人員是否發現了一些合法的魔法來使這一切工作?

+0

Dupe:http://stackoverflow.com/questions/188839/function-pointer-cast-to-different-signature – 2010-01-07 18:48:21

回答

2

C調用約定使得來電者清理堆棧上的參數的責任。所以如果調用者提供了太多的參數,這不是問題。額外的參數被忽略。

所以,是的,你可以投一個函數指針到另一個函數指針類型,具有相同的參數,然後一些,並調用了太多的參數的原始功能,它會工作。

+2

其實,我相信有沒有這樣的事情「的C調用約定「。 C標準沒有對其進行定義,因此編譯器和平臺使用什麼約定。但是,*大多數編譯器/平臺使用您描述的調用約定。 – sleske 2013-09-12 09:55:48

1

在我看來,在這方面,C89的標準是相當混亂。據我所知,他們不禁止從/鑄造沒有PARAM規範運作,所以:

typedef void (*one)(int first); 
typedef void (*two)(int first, int second); 
typedef void (*empty)(); 

one src = something; 
two dst; 

/* Disallowed by C89 standards */ 
dst = (two) src; 

/* Not disallowed by C89 standards */ 
dst = (two) ((empty) src); 

最後,編譯器必須能夠從one轉換爲two,所以我不看不到直接演員的原因。

無論如何,GTK +中的信號處理在幕後使用一些dark magic來管理具有不同參數模式的回調,但這是一個不同的問題。

1

現在,有多酷,我目前正在通過GTK教程工作,並偶然發現了完全相同的問題。

我試了幾個例子,然後用一個簡單的例子問了問題What happens if I cast a function pointer, changing the number of parameters

的回答你的問題(改編自優秀的答案我上面的問題,從問題Function pointer cast to different signature答案):

  • 是的,這是違反C標準的。如果您將函數指針轉換爲不兼容類型的函數指針,則在調用它之前,必須將其轉換回原始(或兼容)類型。其他任何東西都是未定義的行爲。
  • 但是,它在實踐中的作用取決於C編譯器,特別是它使用的調用約定。最常見的調用約定(至少在i386上)恰好只是以相反的順序將參數放在堆棧上,所以如果一個函數需要的參數少於提供的參數,它將只使用第一個參數而忽略其餘參數 - 哪一個正是你想要的。然而,這個將在具有不同調用約定的平臺上打破

所以真正的問題是GLib開發人員爲什麼這樣做。但這是一個不同的問題,我猜...

相關問題