函数指针类型(F)(类型)和类型(类型)(类型)(类型)之间的差异

Difference between Type(f)(Type) and Type(*f)(Type) for function pointers?

本文关键字:类型 之间 函数 指针      更新时间:2023-10-16

这两个函数原型之间有什么区别?

void apply1(double(f)(double));
void apply2(double(*f)(double));

如果目标是将提供的功能应用于数组,那么与另一个版本相比,版本比其他版本更快?

编辑:实现的示例:

#include <iostream>
#include <vector>
#include <cmath>
// First version
template<typename Type> void apply1(std::vector<Type>& v, Type(f)(Type))
{
    for (unsigned int i = 0; i < v.size(); ++i) {
        v[i] = f(v[i]);
    }
}
// Second version
template<typename Type> void apply2(std::vector<Type>& v, Type(*f)(Type))
{
    for (unsigned int i = 0; i < v.size(); ++i) {
        v[i] = f(v[i]);
    }
}
// Main
int main()
{
   std::vector<double> v = {1., 2., 3., 4., 5.};
   apply1(v, std::sin);
   apply2(v, std::sin);
   return 0;
}

首先,模板包装器实例化的速度几乎完全受优化器的摆布。

也就是说,我将您的样本减少到我能想到的最基本的代码,特别是为了检查功能参数的调用。您可以继续阅读,但是您会看到它们调用完全相同。一项声明与另一个声明没有好处。此外,我包括了您遗漏的那个,(参考 - decl)

#include <cstdio>
int hello(int x)
{
    return x;
}
template<typename Type> 
void apply1(Type x, Type (f)(Type))
{
    f(x);
}
template<typename Type> 
void apply2(Type x, Type (*f)(Type))
{
    f(x);
}
template<typename Type> 
void apply3(Type x, Type (&f)(Type))
{
    f(x);
}
int main(int argc, char *argv[])
{
    apply1(1,hello);
    apply2(2,hello);
    apply3(3,hello);
    return 0;
}

扣除额生成的实际ASM是:

apply1

__Z6apply1IiEvT_PFS0_S0_E:
Leh_func_begin2:
    pushq   %rbp
Ltmp2:
    movq    %rsp, %rbp
Ltmp3:
    subq    $16, %rsp
Ltmp4:
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movq    -16(%rbp), %rax
    movl    -4(%rbp), %ecx
    movl    %ecx, %edi
    callq   *%rax
    addq    $16, %rsp
    popq    %rbp
    ret
Leh_func_end2:

apply2

__Z6apply2IiEvT_PFS0_S0_E:
Leh_func_begin3:
    pushq   %rbp
Ltmp5:
    movq    %rsp, %rbp
Ltmp6:
    subq    $16, %rsp
Ltmp7:
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movq    -16(%rbp), %rax
    movl    -4(%rbp), %ecx
    movl    %ecx, %edi
    callq   *%rax
    addq    $16, %rsp
    popq    %rbp
    ret
Leh_func_end3:

apply3

__Z6apply3IiEvT_RFS0_S0_E:
Leh_func_begin4:
    pushq   %rbp
Ltmp8:
    movq    %rsp, %rbp
Ltmp9:
    subq    $16, %rsp
Ltmp10:
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movq    -16(%rbp), %rax
    movl    -4(%rbp), %ecx
    movl    %ecx, %edi
    callq   *%rax
    addq    $16, %rsp
    popq    %rbp
    ret
Leh_func_end4:

它们是相同的(我怀疑它们会)。没有区别,我可以看到

注意:值得一提

apply1: __Z6apply1IiEvT_PFS0_S0_E
apply2: __Z6apply2IiEvT_PFS0_S0_E
apply3: __Z6apply3IiEvT_RFS0_S0_E

void apply1(double(f)(double));
void apply2(double(*f)(double));

这两个功能具有相同的签名,因此没有差异。他们都采用一个指针来函数参数。

ISO/IEC 14882:2011 8.3.5 [DCL.FCT]/5:

确定每个参数的类型后,将" t"或" tharm返回t"类型的任何参数调整为"指向t"或"指针"或"指针函数返回t"。

我会尝试使它更简单。

#include <stdio.h>
void my_int_func(int x)
{
    printf( "%dn", x );
}
int main()
{
    void (*foo)(int);
    // the ampersand is actually optional
    foo = &my_int_func;
    return 0;
}

您可以看到上面的函数,该函数需要一个整数并返回一个空白。在MAIN内部,我正在用My_int_func.进行函数指针FOO。请仔细查看评论" ampersand是可选的"。实际上,它说明了所有。

因此,您的两个陈述都没有区别。