假设有一个函数指针:
void func(float a1, float a2) {
}
void (*fptr)(float, float) = &func;
这两行之间是否有任何区别(编译和编译都是如此)?
(*fptr)(1,2);
fptr(1,2);
我认为第二个版本只是第一个版本的快捷方式,但我想确保自己。更重要的是它是一种标准行为吗?
答案 0 :(得分:6)
是的,它是标准行为,适用于所有C编译器。
函数调用实际上总是通过指向函数的指针进行:
6.5.22“函数调用”:
表示被调用函数的表达式(脚注77)应具有指向函数的类型指针返回void或返回除数组类型之外的对象类型
如脚注77所示,当使用函数调用表达式时,“正常”函数标识符实际上转换为指向函数的指针:
脚注77:
通常,这是转换作为函数指示符的标识符的结果。
有趣的是,取消引用函数指针(或转换为函数指针的函数指示符)会产生函数的函数指示符,该函数指示符将被转换回函数调用表达式的函数指针。所以你可以取消引用函数指针(或普通函数名),但不必。
6.5.3.2/4“地址和间接操作符”:
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator
就标准而言,就你的例子而言:
(*fptr)(1,2);
fptr(1,2);
第二个并不是简写 - 这是编译器所期望的。实际上,第一个例子实际上只是一个更冗长的方式来表达与第二个相同的东西。但有些人可能更喜欢第一种形式,因为它更清楚地表明正在使用指针。生成的代码应该完全没有区别。
标准措辞的另一个结果是您也可以取消引用正常的函数名称:
func(1,2);
(*func)(1,2); // equivalent to the above
并不是说我能想到的确实有任何防御性的观点。
答案 1 :(得分:6)
他们做同样的事情。
函数调用的前缀始终是指向函数类型的表达式。
指针类型的表达式,例如声明的函数的名称。隐式转换为指向该函数的指针,除非它是一元"&"
(无论如何产生函数的地址)或sizeof
的操作数(这是非法的而不是产生指针的大小)
这条规则的结果是所有这些:
&func
func
*func
**func
是等价的。它们都评估函数的地址,并且它们都可以(如果适当地加括号)用作函数调用的前缀。