C – 地址运算符中的函数指针“不必要”

在C中使用qsort我们传递比较函数,例如

int cmp(const void*, const void*); 

qsort的protoype期望一个int(*)(const void *,const void *)所以我们调用:

 qsort(..., cmp); 

但同样有效的是:

 qsort(..., &cmp); 

如果我们在C ++中传入静态成员函数,这就是我们必须要做的。 Kernighan&Ritchie(第2版,5.11“Pointers To Functions”p119)声明“因为[cmp]已知是一个函数,所以&运算符不是必需的,就像在数组名称之前不需要它一样。 “

是否有人对此感到有点不舒服(特别是关于型号安全性)?

无论您是否感到不舒服,都不会改变C不被视为类型安全语言的事实。 例证:

 int main() { int integer = 0xFFFFFF; void (*functionPointer)() = (void(*)())integer; functionPointer(); return 0; } 

这在编译时完全有效,但显然不安全。

嗯,答案是按值传递函数会产生一个函数指针,就像通过value传递数组一样,会产生一个指向其第一个元素的指针。 一个人说arrays和function“衰变”。 只有少数情况下不会发生衰变。 例如sizeof(array)产生数组的大小,而不是它的第一个元素指针之一。 sizeof(函数)无效(函数不是对象),你必须做sizeof(&function)。 其他场合绑定参考:

 void baz(); void foo(void (&bar)()) { bar(); } // doesnt work, since a reference to a function is requested. // you have to pass 'bar' itself, without taking its address // explicitely. foo(&baz); 

这个,顺便说一句就是你能做到的

 template void ByRef(T (&foo)[N]) { ... } 

因为在考虑参考参数时arrays还没有衰减。

我怀疑你只是觉得不舒服,因为你不习惯像C允许的那样编码’接近金属’。 C不需要函数地址运算符的原因是除了调用它们或传递它们之外,没有什么可以用于函数。

换句话说,没有合理的定义来操纵函数的“价值”。

使用整数,您可以添加或减去该值,这对函数没有意义。

在任何情况下,C都早于C ++和它自己的标准化 – 原始的K&R C甚至没有原型,ANSI必须确保它们的标准化不会尽可能地破坏现有代码。

这是一个语法细节。 如果您不喜欢不使用&来指示函数指针,那么请始终使用它。 如果你喜欢保存额外的按键而不是在你的编码中那么明确,那就利用它。

至于类型安全,我看不出它有什么区别。 编译器被赋予一个函数作为参数,它可以从名称中找出函数签名的全部内容。 你没有调用它(使用()语法)的事实给出了编译器需要你在这个位置需要函数指针的所有指示。 &只是一种语法精确,向人类表明他们正在寻找一些描述的指针。

如果您正在使用C ++,那么我建议将boost仿函数看作是一种更好的传递函数的方法。 这些可爱的实体为C ++中的所有函数提供了统一且相当清晰的语法:)

对于有效但有冲突的语法选项的厌恶并不是一种不适感。 要么cmp是指针,要么应该一致地对待它,或者它是其他类型 – 恕我直言,语法错误。

更进一步,我还需要调用取消引用指针(以突出显示它是指针的事实)或不(因为函数名称指针)…但不允许两者。

函数指针可以非常强大,但它们似乎是新手和有经验的程序员的混淆源。 部分难度可以通过要求单一,有意义的语法来澄清其使用而不是模糊它来缓解。

请注意,“解除引用”(即调用)函数指针也是如此; 你不必

 (*funcptr)(arg1, arg2); 

 funcptr(arg1, arg2); 

就足够了。