C - 地址运算符中的函数指针"不必要"

chr*_*umb 7 c c++ function-pointers

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

int cmp(const void*, const void*);
Run Code Online (Sandbox Code Playgroud)

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

qsort(..., cmp);
Run Code Online (Sandbox Code Playgroud)

但同样有效的是:

qsort(..., &cmp);
Run Code Online (Sandbox Code Playgroud)

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

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

Jef*_*man 8

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

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

   functionPointer(); 

   return 0; 
}
Run Code Online (Sandbox Code Playgroud)

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

  • 是的,但使用该演员阵容是告诉编译器"信任我;我知道我在做什么,即使你不这么认为". (4认同)

pax*_*blo 5

我怀疑您只是感到不舒服,因为您不习惯像 C 允许的那样“接近金属”进行编码。C 不需要函数的地址运算符的原因是,除了调用它们或传递它们之外,您实际上无法对函数做任何事情。

换句话说,对于操作函数的“值”没有合理的定义。

而对于整数,您可以对值进行加法或减法,这对函数来说毫无意义。

无论如何,C 早于 C++ 和它自己的标准化——最初的 K&R C 甚至没有原型,ANSI 必须确保他们的标准化尽可能不破坏现有代码。

  • 肯定有。您可以执行 functionptr++ 并对堆栈做坏事。;) (2认同)

Joh*_*itb 5

嗯,答案是按值传递函数会产生一个函数指针,就像通过值传递数组一样,会产生一个指向其第一个元素的指针.一个人说阵列和功能"衰变".只有少数情况下不会发生衰变.例如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);  
Run Code Online (Sandbox Code Playgroud)

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

template<typename T, int N>
void ByRef(T (&foo)[N]) { 
    ...
}
Run Code Online (Sandbox Code Playgroud)

因为在考虑参考参数时阵列还没有衰减.