我们可以混合__extension__和-std = c99吗?

时间:2017-08-15 08:32:01

标签: c gcc-warning gcc-extensions

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

  

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

glib / 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);
}

gpointertypedef的{​​{1}},而void *使用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程序。 / p>

我的问题是:

我们可以将-std=c99__extension__结合使用,还是我们被迫使用-std=gnu99

换句话说,__extension__是否意味着(强制)使用扩展进行编译,或者只是使编译器静音的指令,而我的程序是在未定义的行为下工作的?

1 个答案:

答案 0 :(得分: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语法 - 违反简单赋值的约束。