1

该标准不允许在指向函数的指针void *和指向函数的指针之间进行转换:

6.3.2.3:8 指向一种类型函数的指针可以转换为指向另一种类型函数的指针,然后再转换回来;结果应与原始指针比较。如果转换后的指针用于调用类型与指向的类型不兼容的函数,则行为未定义。

glib/gtk 中有几个函数打破了这个规则,一个例子是g_signal_handlers_block_by_func

在 a 中转换为大写的典型示例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);
}

gpointer是一个typedefforvoid *g_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__暗示(强制)使用扩展进行编译,或者只是一条使编译器静音的指令,并且我的程序正在未定义的行为下工作?

4

1 回答 1

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 语法 - 违反简单赋值的约束。
于 2017-08-15T08:46:15.407 回答