在GTK库中,可以找到以下定义:
/**
* GCallback:
*
* The type used for callback functions in structure definitions and function
* signatures. This doesn't mean that all callback functions must take no
* parameters and return void. The required signature of a callback function
* is determined by the context in which is used (e.g. the signal to which it
* is connected). Use G_CALLBACK() to cast the callback function to a #GCallback.
*/
typedef void (*GCallback) (void);
假定这是不带参数且不返回的void
函数指针的typedef 。
但是,在GTK站点的Hello World示例中,显示了以下代码:
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
其中activate
有一个返回void
但带有两个参数的函数。(G_CALLBACK
是简单地转换为的宏GCallback
)。
确实GCallback
-typedef上方的注释表明:
这并不意味着所有回调函数都必须不带任何参数并返回void
该代码确实可以编译并运行。那怎么可能呢?
C11标准的§6.3转换,更精确的是§6.3.2.3指针¶8表示:
可以将指向一种类型的函数的指针转换为指向另一种类型的函数的指针,然后再次返回。结果应等于原始指针。如果使用转换后的指针来调用其类型与引用的类型不兼容的函数,则该行为是不确定的。
GTK代码使程序员有责任将适当类型的函数指针传递给进行回调的函数。
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
其中
activate
有一个返回void
但带有两个参数的函数。(G_CALLBACK
是简单地转换为的宏GCallback
)。
假设两个参数为int
; 它们的类型与讨论是巧合的。
extern void activate(int, int);
中的代码g_signal_connect()
获取4个指针。第三个是回调;它是形式上的void (*callback)(void)
。
里面的代码g_signal_connect()
期望使用2个整数(arg1
和arg2
)调用回调,因此需要使用:
((void (*)(int, int)callback)(arg1, arg2);
强制将“通用”类型callback
转换为正确的函数指针类型-否则,它无法避免调用未定义的行为。您需要知道g_signal_connect()
需要这样的指针作为回调参数,并强制转换为泛型类型,并且您必须将适当的指针传递给它。
还要记住,展现“不确定行为”的一种方法是“表现出预期,即使标准并不能保证预期”。表现出未定义行为的其他方式包括崩溃或破坏内存。
边注。
C11 §6.2.5类型¶28说:
指向的指针
void
应具有与指向字符类型的指针相同的表示和对齐要求。48)同样,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针应具有相同的表示和对齐要求。指向联合类型的所有指针应具有相同的表示和对齐要求。指向其他类型的指针不必具有相同的表示或对齐要求。48)相同的表示形式和对齐要求旨在表示与函数的参数,函数的返回值和并集的成员具有互换性。
§6.3.2.3¶8的要求似乎暗示着所有指向不同函数类型的指针必须具有相同的表示和对齐要求。否则,很难保证第6.3.2.3¶8段的往返转换要求。
§6.2.5¶28的另一个结果是,您不能在指向函数类型的指针和指向对象类型的指针(例如)之间可靠地转换void *
。这会对诸如以下功能产生影响dlsym()
:很难干净地使用它们-如果启用了严格的警告级别,编译器可能会抱怨。
编译一些在函数指针和对象指针之间转换的代码(反之亦然),GCC 9.3.0具有以下功能gcc -std=c99 -O3 -Wall -pedantic -Wdeclaration-after-statement -Wold-style-definition -Wold-style-declaration -Wnested-externs -Wmissing-prototypes -Werror …
:
…: error: ISO C forbids conversion of function pointer to object pointer type [-Werror=pedantic]
…: error: ISO C forbids conversion of object pointer to function pointer type [-Werror=pedantic]
这是一个警告,如果你没有-Werror
或-pedantic-errors
有效的,如果你没有它忽略-pedantic
或-pedantic-errors
有效。
请注意-pedantic
(aka -Wpedantic
)和之间的差异-pedantic-errors
,如GCC在“请求或禁止警告的选项”下所述。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句