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

gpointertypedefforvoid *であり、次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 に答える