【问题标题】:Why are both these function pointers legal in C/C++?为什么这两个函数指针在 C/C++ 中都是合法的?
【发布时间】:2023-03-17 21:20:02
【问题描述】:

我有这两个测试功能:

int apply_a(int (*fun)(int, int), int m, int n) {
    return (*fun)(m,n);
}

int apply_b(int (*fun)(int, int), int m, int n) {
    return fun(m,n);
}

它们似乎返回不同的东西,那么为什么它们都产生相同的结果?

int add(int a, int b) {return a + b;}

int res_a = apply_a(add, 2, 3); // returns 5
int res_b = apply_b(add, 2, 3); // returns 5

我会假设其中一个会返回指针地址或指针本身;而不是存储在指针上的值...

那么为什么要这样做呢?

【问题讨论】:

  • 因为任何一种语法(带或不带星号)对于通过指针调用函数都是有效的。第二种情况是调用(你可以通过括号和传递的参数来判断)。
  • 两者都不好。你应该使用(***fun)(m, n) 来获得三星级程序员的资格。

标签: c++ c pointers return function-pointers


【解决方案1】:

因为在处理非成员函数的地址和使用指向它们的指针时,C++ 提供了语法糖。

可以得到该函数的地址:

int someFunc(int);

与任一:

int (* someFuncPtr)(int) = someFunc;

或:

int (* someFuncPtr)(int) = &someFunc;

也有使用这种指针的语法糖,或者调用指向函数:

(*someFuncPtr)(5);

或使用简化语法:

someFuncPtr(5);

【讨论】:

  • 请记住,这同样适用于静态类方法(至少在我检查过的 Visual C++ 2012 上))
  • 这也适用于 C 语言吗?还是仅适用于 C++ 的糖规则?
  • C++ 为“函数”类型引入了另一种表示法:int(int),它可以转换为int(*)(int)someFunc 的类型为 int(int),而 &someFunc 的类型为 int(*)(int)
  • @ElectricCoffee,它也适用于 C。
【解决方案2】:

(*fun)(m,n)fun(m,n) 相同,这是因为 C 和 C++ 中的规则将函数转换为指向函数的指针。

在 C 2011 中,规则是第 6.3.2.1 4 条:“函数指示符是具有函数类型的表达式。除非它是 sizeof 运算符、_Alignof 运算符 或一元 & 运算符的操作数,否则为“函数返回”类型的函数指示符type”被转换为具有“指向返回type的函数的指针”类型的表达式。在 C++ 中,规则是第 4.3 条。

请注意,函数指示符不仅仅是命名函数的标识符。它可以是一个标识符,也可以是另一个表达式。比如foo是一个函数的名字,上面会自动转换成指向函数的指针。那么,由于foo 是指向函数的指针,所以*foo 就是函数。这意味着你可以写:

(*fun)(m,n)

结果是fun 自动转换为指针,然后* 计算为函数,然后*fun 转换回指针,然后调用函数。你可以继续写:

(**************fun)(m,n)

这与fun(m,n) 相同。每个* 都会再次生成函数,但编译器会自动将其转换回指针。您可以永远继续这场战斗,但编译器将永远获胜。

其实这些都是一样的效果:

(&fun)(m,n)
( fun)(m,n)
(*fun)(m,n)

【讨论】:

    【解决方案3】:

    这是因为您没有返回这些值的内存地址。 用指针调用函数不会改变它的值,它仍然在调用函数。您可以做的是将一个值返回给一个变量,然后获取它的内存地址,例如:

    int result = fun(m,n);
    cout << "the result " << result << " pointing at " << &result << endl;
    

    【讨论】:

      【解决方案4】:

      在 C 和 C++ 中,函数的名称也是指向函数代码的指针。作为任何指针,您可以使用* 取消引用它们,这在函数指针的情况下意味着调用函数,除了取消引用之外,您还可以在它们之后使用括号,就像在您的apply_a 案例中一样。但对 C 和 C++ 函数的有效调用也只是通过它们的名称来调用它们,即 apply_b 大小写。

      【讨论】:

      • 这不是名字。 任何函数表达式,而不仅仅是函数名,都将被转换为指向函数的指针。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      • 2014-12-04
      • 2011-07-15
      • 1970-01-01
      • 2016-08-05
      • 2012-01-10
      • 2018-06-12
      相关资源
      最近更新 更多