Can we mix __extension__ and -std=c99?

400 Views Asked by At

The standard doesn't allow to convert between pointers to void * and pointers to functions:

6.3.2.3:8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

There are several functions in glib/gtk breaking this rule, an example is g_signal_handlers_block_by_func

A typical example converting to uppercase in 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 is a typedef for void * and g_signal_handlers_unblock_by_func is implemented using 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))

Thus, compiling this code using -std=c99 gives the following warning:

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);

And the only way I can find to silence the compiler is using __extension__:

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

Sorry for such long preamble but as you can see glib / gtk is using gcc extensions and there is no way to compile in -pedantic mode (without warnings) a gtk program using signal handlers.

My question is:

Can we use -std=c99 in conjunction with __extension__ or we are forced to use -std=gnu99?

In other words, does __extension__ implies (forces) compiling with extensions or is just an instruction to silence the compiler and my program is working under undefined behaviour?

1

There are 1 best solutions below

2
Lundin On

What you can do if you know that object pointers and function pointers have the same representation on the given platform, is to convert to an integer type in between.

Conversions can be done between integers and all pointer types - it is not undefined but merely implementation-defined behavior (6.3.2.3, §4 and §5).

Example:

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

This is implementation-defined behavior and should not generate diagnostics.

Note that:

  • void* vptr = fptr; is an invalid conversion/undefined behavior.
  • void* vptr = (uintptr_t)fptr; is invalid C syntax - constraint violation of simple assignment.