1

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?

David Ranieri
  • 39,972
  • 7
  • 52
  • 94

1 Answers1

2

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.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • @KeineLust As far as I know, `__extension__` is just a way to silence the warnings, so I think it is only meaningful to use together with the strict settings, ie `-std=c99 -pedantic-errors`. If you use `-std=gnu99` you wouldn't be getting warnings from using non-standard extensions. – Lundin Aug 15 '17 at 09:02
  • Strange but I get the same warning using `-gnu99` if `__extension__` is not used, my cflags are `-std=gnu99 -pedantic -Wall -Wextra -W -Wmissing-prototypes -Wstrict-prototypes -Wconversion -Wshadow -Wcast-qual -Wnested-externs` – David Ranieri Aug 15 '17 at 09:07