我反复讨论在GTK +代码中设置信号处理程序的问题,不需要几个参数,并试图使用与处理程序相同的函数来处理多个信号,其处理程序具有不同的签名 - 但是使用前N个参数(我关心的那些)同样的.
它是否安全(在某种意义上它不是未定义的行为,而不是更实用的"它在我的PC上工作吗?")将指针传递给GObject API,当这些函数期望参数少于它们时实际上是从信号发射过程中获得的?
或者,将此与GTK +离婚,这段代码还可以吗?
/* Note: No void *userdata argument! */
void show(int x) {
printf("x = %d\n", x);
}
void do_stuff(void (*fn)(int, void *), void *userdata) {
static int total = 0;
(*fn)(total, userdata);
total++;
}
void doitnow(void) {
do_stuff(&show, NULL);
}
Run Code Online (Sandbox Code Playgroud)
要获得额外的功劳,请讨论功能签名和呼叫站点之间不同返回值类型的含义.
编辑:一个几乎相同的问题更密切地探测"兼容的函数类型",并直接解决我的具体问题 - 链接GObject信号处理程序.TL; DR:是的,它是未定义的行为,但它在某些工具包中实际上是惯用的(尽管不是强制性的).
根据6.5.2.2第9段,它是明确未定义的行为:
如果函数定义的类型与表示被调用函数的表达式指向的类型(表达式)不兼容,则行为未定义.
show定义的类型,
void show(int x)
Run Code Online (Sandbox Code Playgroud)
与调用它的指针所指向的表达式类型不兼容,
void (*fn)(int, void *)
Run Code Online (Sandbox Code Playgroud)
同样明确地在6.3.2.3第8段中:
指向一种类型的函数的指针可以被转换为指向另一种类型的函数的指针并且再次返回; 结果应该等于原始指针.如果转换的指针用于调用类型与引用类型不兼容的函数,则行为未定义.
对于函数,"兼容类型"的特征在6.7.6.3(15)[C99中的6.7.5.3(15)]:
要使两种函数类型兼容,两者都应指定兼容的返回类型.此外,参数类型列表(如果两者都存在)应在参数的数量和省略号终止符的使用中一致; 相应的参数应具有兼容的类型.如果一个类型具有参数类型列表而另一个类型由函数声明符指定,该函数声明符不是函数定义的一部分并且包含空标识符列表,则参数列表不应具有省略号终止符,并且每个参数的类型应为与应用默认参数促销产生的类型兼容.如果一个类型具有参数类型列表而另一个类型由包含(可能为空)标识符列表的函数定义指定,则两者应在参数数量上一致,并且每个原型参数的类型应与类型兼容这是因为默认参数促销应用于相应标识符的类型.(在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数都被视为具有调整类型,并且使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本.)
这里最直接相关的部分是参数的数量必须相同.