也许标题本身并不清楚......
我有一个函数f(由某些库提供),它将签名void g(int*)
的函数指针作为参数,即
void f(void (*g)(int*));
但是,我想使用带有签名g
的函数void g(const int*)
(我定义的)来使用它。先验,我无法看到这会如何违反任何常规正确性,因为f
的所有签名都表示g
只会被调用(非const
}}} int*
(非 - const
),实际上我可以使用非void (const int*)
const
参数调用int*
函数。
但GCC抱怨并说,
expected 'void (*)(int *)', but argument is of type 'void (*)(const int *)'
我无法看到此投诉是如何合法的,所以有人知道我对此的理解是否错误,或者是否有解决办法?
答案 0 :(得分:6)
您似乎找到了编译器编写者和标准编写者未考虑的内容。来自C99草案n1256,§6.7.5.3第15段,
相应的参数应具有兼容的类型。
请注意,const int *
与int *
不兼容。但是,int *
可能会转换为const int *
。来自§6.3.2.3,第2段,
对于任何限定符 q ,指向非 q - 限定类型的指针可能会转换为指向 q - 限定的指针
的版本
用于推断替换从相同类型的合格或非限定版本派生的类型何时可接受的更复杂的规则在标准中根本不存在。因此,您的代码在技术上违反了标准。
我的结论:在我看来,编译器应该将此错误视为“迂腐”:您的代码技术上符合标准,但是意思是明确的,代码是绝对安全的。随意向您的编译器供应商写一个功能请求。有许多不符合要求的做法,如果没有-pedantic
,就不会产生警告。
作为最后一点,我和Clang一起编辑,编辑告诉我警告是迂腐的。但是,我没有要求迂腐警告......所以似乎无法将其关闭。
warning: incompatible pointer types passing 'void (int const *)', expected 'void (*)(int *)' [-pedantic]
解决方法:使用显式广播。
void g(const int *);
f((void (*)(int *)) g);
答案 1 :(得分:3)
你是对的,没有理由C不应该禁止这个电话(除了因为C标准说它应该)。 U(*)(T*)
应该是U(*)(const T*)
的子类型,因为int*
是可替代性的const int*
的子类型。
为什么C不允许这样做,我不知道。
至于解决方法,您可以提供代理功能:
void foo(const int* x) { ... } // <-- the function you want to pass in
void bar(int* x) { foo(x); } // proxy
f(bar); // instead of f(foo)
使用像这样的安全,符合标准的代理工作的事实应该足够证明该调用本来应该是有效的。