2017-08-15 140 views
1

標準不允許指針void *和指針之間轉換爲功能:我們可以混合使用__extension__和-std = c99嗎?

6.3.2.3:8一個指針,指向一個類型的函數可被轉換成一個指針到另一個類型的函數再回來;結果應該等於原始指針 。如果使用轉換的指針 調用類型與指向的 類型不兼容的函數,則行爲未定義。

有在油嘴/ GTK幾個功能打破該規則,作爲一個例子g_signal_handlers_block_by_func

一個典型的例子轉換在GtkEntry爲大寫:

void 
insert_text_handler (GtkEditable *editable, 
        const gchar *text, 
        gint   length, 
        gint  *position, 
        gpointer  data) 
{ 
    gchar *result = g_utf8_strup (text, length); 

    g_signal_handlers_block_by_func (editable, 
           (gpointer) insert_text_handler, data); 
    gtk_editable_insert_text (editable, result, length, position); 
    g_signal_handlers_unblock_by_func (editable, 
            (gpointer) insert_text_handler, data); 

    g_signal_stop_emission_by_name (editable, "insert_text"); 

    g_free (result); 
} 

gpointervoid *typedefg_signal_handlers_unblock_by_func使用gpointer實施:

guint g_signal_handlers_block_matched(gpointer instance, 
          GSignalMatchType mask, 
          guint   signal_id, 
          GQuark   detail, 
          GClosure  *closure, 
          gpointer  func, 
          gpointer  data); 

#define g_signal_handlers_block_by_func(instance, func, data)       \ 
    g_signal_handlers_block_matched((instance),        \ 
          (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), \ 
          0, 0, NULL, (func), (data)) 

因此,編譯使用-std=c99此代碼提供了以下警告:

src/client/gui.c: In function ‘insert_text_handler’: 
src/client/gui.c:474:45: warning: ISO C forbids conversion of function pointer to object pointer type [-Wpedantic] 
    g_signal_handlers_block_by_func(editable, (gpointer)insert_text_handler, data); 

而且我能找到沉默編譯器的唯一方法是使用__extension__

__extension__ g_signal_handlers_block_by_func (editable, (gpointer)insert_text_handler, data); 

對不起,這麼長的序言但正如你所看到的,glib/gtk使用的是gcc擴展,並且無法使用信號處理程序在-pedantic模式(沒有警告)編譯gtk程序。

我的問題是:

我們能否一起使用-std=c99__extension__或者我們被迫使用-std=gnu99

換句話說,__extension__意味着(強制)與擴展編譯還是隻是一個指令,以沉默編譯器和我的程序工作在未定義的行爲?

回答

2

你可以做什麼,如果你知道該對象的指針和函數指針具有給定的平臺上相同的表示,就是要轉換爲整數之間鍵入英寸

可以在整數和所有指針類型之間進行轉換 - 它不是未定義的,而僅僅是實現定義的行爲(6.3.2.3,§4和§5)。

實施例:

typedef void funcptr_t (void); 
... 
funcptr_t* fptr = func; 
void* vptr = (void*)(uintptr_t)fptr; 

這是實現定義的行爲,不應產生診斷。

需要注意的是:

  • void* vptr = fptr;是一個無效的轉換/未定義行爲。
  • void* vptr = (uintptr_t)fptr;無效C語法 - 約束違反簡單賦值。
+0

@KeineLust據我所知,'__extension__'只是一種沉默警告的方法,所以我認爲它只與嚴格設置一起使用纔有意義,即'-std = c99 -pedantic-errors '。如果你使用'-std = gnu99',你將不會收到使用非標準擴展的警告。 – Lundin

+0

奇怪,但如果沒有使用__extension__,我會使用'-gnu99'得到相同的警告,我的cflags是'-std = gnu99 -pedantic -Wall -Wextra -W -Wmissing-prototypes -Wstrict-prototypes -Wconversion -Wshadow - Wcast-qual -Wnested-externs' –

相關問題