我有一个函数指针,其函数被声明为 char *
参数。into,我想将指针保存到被声明为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?
这是未定义的行为 - 您可以使用指针来调用其他类型的函数,而当类型兼容时( 6.3.2.2.3/8 ):
指向一种类型函数的指针可以转换为指针转换为另一种类型的函数,然后再次返回;结果应与原始指针相等。如果使用转换的指针来调用与引用类型不兼容的函数,则该行为是未定义的。
如果(简化版本)它们具有相同的返回,并且参数是兼容的( 6.7.6.3,Sentics/15 ):
对于要兼容的两种函数类型,两者均应指定兼容的返回类型。146)此外,如果两者都存在,则参数类型列表应在参数数量和使用eLLIPSIS终止器中同意;相应的参数应具有兼容类型。
a const char *
与 char *
不兼容( 6.7.6.1,语义/2 ):
对于两种指针类型兼容,两者均应相同的资格,并且两者都应是兼容类型的指针。
由于const char *
和char *
没有相同的资格,它们不兼容,并且通过b
调用write_b
是未定义的行为。
严格来说,不允许。
pointer-to-something
与pointer-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
不是const-correct。如果您无法更改该功能,请在其周围写一个包装器。
write_fn b1 =(write_fn)write_b;//这是合法的吗?
是什么法律?
涉及此演员的功能指针类型不兼容。
然而铸造功能指针指向不兼容的功能指针类型是完全合法的。但是,使用这种有力转换的指针可以做的唯一可以将其转换回原始类型。语言规范确保这种往返转换将保留原始的指针值。这就是为什么我们可以将void (*)(void)
用作功能指针的"通用存储类型"(例如用于数据指针的void *
)的原因。它可用于任何类型的存储函数指针(但不能用于呼叫函数)。要执行此类指针存储(和检索),我们将不得不使用明确的铸件,就像代码中的铸件一样。没有什么是违法的。
同时,尝试通过b1
调用该函数将导致不确定的行为,特别是因为指针类型与实际功能类型不兼容。
在您的问题中,您清楚地表明您要"保存"指向该功能的指针。只要我们只谈论"保存"(存储)指针,您的代码非常完美。