【发布时间】:2011-08-16 04:55:01
【问题描述】:
如果我们有
void f() {
printf("called");
}
那么下面的代码会输出“被调用”:
f();
(*f)();
我不太明白这是怎么工作的……*f 和 f 有什么区别?为什么要使用后一种语法调用函数?
【问题讨论】:
-
这需要两个问题,一个是关于C的,一个是关于C++的,因为它们有微妙的不同规则(虽然最终的行为相同)。
如果我们有
void f() {
printf("called");
}
那么下面的代码会输出“被调用”:
f();
(*f)();
我不太明白这是怎么工作的……*f 和 f 有什么区别?为什么要使用后一种语法调用函数?
【问题讨论】:
C++中有两种调用函数的方式:
按名称:
f();
通过函数指针:
typedef void (*fptr_t)();
fptr_t fptr = &f;
(*fptr)();
现在,在函数名 (&f) 上使用地址运算符显然会创建一个函数指针。但是当满足某些条件时,函数名可以隐式转换为函数指针。所以上面的代码可以写成:
typedef void (*fptr_t)();
fptr_t fptr = f; // no address-of operator, implicit conversion
(*fptr)();
您的第二个示例正是这样做的,但使用临时变量而不是命名局部变量来保存函数指针。
我更喜欢在创建函数指针的时候使用address-of,意思更清楚。
相关说明:如果提供了函数指针,函数调用运算符将自动取消对函数指针的引用。所以这也是合法的:
typedef void (*fptr_t)();
fptr_t fptr = &f;
fptr();
这对模板非常有用,因为无论您传入的是函数指针还是函子(实现operator() 的对象),相同的语法都适用。
这两种快捷方式都不适用于指向成员的指针,因此您需要显式的地址和取消引用运算符。
在 C 中,@Mehrdad explains that all function calls use a function pointer.
【讨论】:
第一个在某种程度上是第二个的语法糖。第二个很明显您是通过指针进行调用的,它主要用于函数指针而不是常规函数,以使区别更加明显。
【讨论】:
f,然后通过它调用函数吗?
* 符号有多种含义——它既可以是解引用 operator,也可以是指针 declaration,除了乘法。不要混淆它们。)
(*&f)();,但这只是由于C的继承。在 C++ 中,您“应该”显式获取地址。
f 和*f 是同一个东西,因为间接运算符在应用于函数时,返回一个与函数本身相同的函数指示符。对此进行了详细讨论here。
就像数组类型几乎完全等价于对应的指向元素类型一样,函数类型也完全等价于对应的指向函数类型:
void (*func1)() = f; // function type -> pointer-to-function type
void (*func2)() = &f; // pointer-to-function type -> pointer-to-function type
还有
void (*func)() = ...;
func(); // pointer-to-function type + function-call operator
(*func)(); // function type + function-call operator
所以,在
(*f)();
您正在取消引用 f(隐式转换为 &f),然后应用函数调用运算符。
【讨论】: