传递`int(*)(char const *)`其中`int(*)(char *)`是预期的

时间:2016-12-01 14:31:44

标签: c pointers function-pointers

我有一个函数指针,其函数被声明为期望char *个参数。如果它,我想保存一个指向声明为接受char const*参数的函数的指针。

我想我可以使用包装器或转换器。 转换似乎更直接,但我可以合法地调用这样的函数指针的结果吗?

以下示例代码:

static int write_a(char * X){
    return 0;
}

static int write_b(char const* X){
    return 0;
}
static int wrapped_write_b(char * X){
    return write_b(X);
}

typedef int (*write_fn)(char * );

write_fn a = write_a;
write_fn b = wrapped_write_b;
write_fn b1 = (write_fn)write_b; //is b1 legally callable?

3 个答案:

答案 0 :(得分:10)

这是未定义的行为 - 只有在类型兼容( 6.3.2.3 / 8 )时,您才可以使用指针调用其他类型的函数:

  

指向一种类型的函数的指针可以转换为指向另一种类型的函数的指针,然后再返回;结果应该等于原始指针。如果转换的指针用于调用类型与引用类型不兼容的函数,则行为未定义。

两个函数具有兼容类型,如果(简化版本)它们具有相同的返回值且参数是兼容的( 6.7.6.3,Semantics / 15 ):

  

对于两个兼容的函数类型,两者都应指定兼容的返回类型.146)此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用中一致;相应的参数应具有兼容的类型。

const char *char * 6.7.6.1,Semantics / 2 不兼容):

  

要使两个指针类型兼容,两者都应具有相同的限定条件,并且两者都应是兼容类型的指针。

由于const char *char *不具有相同的限定条件,因此它们不兼容,并且通过write_b调用b是未定义的行为。

答案 1 :(得分:3)

严格来说,这是不允许的。

pointer-to-somethingpointer-to-qualified-something不兼容。因为pointer-to-qualified-something不是pointer-to-something

的合格类型

同样适用于

pointer-to-function-accepting-something

pointer-to-function-accepting-qualified-something

这可以通过C11 6.2.7兼容类型找到:

  

如果类型相同,则两种类型具有兼容类型。   确定两种类型是否兼容的附加规则是   在6.7.2中描述的类型说明符,在6.7.3中表示类型   限定符...

6.7.3是相关部分。它说

  

要兼容两种合格类型,两者都应具有相同类型的兼容类型;

转换章节6.3.2.3与此并不矛盾:

  

指向一种类型的函数的指针可以转换为指向另一种函数的指针   打字再回来;结果应该等于原始指针。 如果转换了   指针用于调用类型与引用类型不兼容的函数,   行为未定义。

修改

正如Holt的回答所述,6.7.6.3/15中明确描述了两个函数的兼容性。

我仍然认为包装函数是最佳解决方案。问题的根源是write_a不是常量。如果你不能改变那个功能,那就写一个包装器。

答案 2 :(得分:2)

  

write_fn b1 =(write_fn)write_b; //这是合法的吗?

是合法的吗?

此演员表中涉及的函数指针类型不兼容。

然而,将函数指针指向不兼容的函数指针类型是完全合法的。但是,使用这种强制转换指针唯一可以做的就是将其转换回原始类型。语言规范保证这种往返转换将保留原始指针值。这就是为什么我们可以使用void (*)(void)作为"通用存储类型"用于函数指针(如数据指针的void *)。它可以用于存储任何类型的函数指针(但不能用于调用函数)。要执行这样的指针存储(和检索),我们必须使用显式转换,就像代码中的转换一样。没有任何违法行为。

同时,尝试通过b1调用该函数将导致未定义的行为,特别是因为指针类型与实际函数类型不兼容。

在你的问题中,你清楚地表明你想要"保存"指向该函数的指针。只要我们只谈论"保存" (存储)指针,你的代码完美无瑕。