【问题标题】:Why does it seem that func is the same as &func in C? [duplicate]为什么 func 看起来与 C 中的 &func 相同? [复制]
【发布时间】:2021-02-19 10:08:08
【问题描述】:

根据GNU C manual,可以使用函数指针调用函数,如下所示:

func (j);  /* (*func) (j); would be equivalent. */

所以我的推理是:func 本身是一个指向func(int) 函数的指针。当您调用func(j) 时,您正在隐式访问指针func 的值(您正在移动到func 所在的内存位置),就像您有一个指向整数的指针时一样,例如,然后您使用* 访问存储在该内存位置中的值。这与您可以使用 (*func)(j) 调用相同的函数这一事实一致。

事实上,在cprogramming.com 中,他们说你可以拥有一个指向函数指针的指针。因此,我猜测它们的工作方式与任何其他类型的指针一样。

但如果是这样,为什么这段代码可以工作?

#include <stdlib.h>
#include <stdio.h>

void a(int n) {
    printf("%d\n", num);
}

int main() {
    int x = 5;
    void (*func)(int); // Declare a pointer to a function
    func = &a; // Pointer to a pointer to a function
    (*func)(x); // Calls the function (why?)
    func = a; // Pointer to a function
    (*func)(x); // Calls the function (makes sense)
}

此外,如果你打电话:

printf("%s\n", (&a == a) ? "True" : "False");

打印True!

例如,我确定&amp;foo&amp;&amp;foo 不一样,所以为什么func 似乎与&amp;func 相同强>?

【问题讨论】:

  • 数组也是如此。如果a 是一个数组,则a == &amp;a 为真。因为数组在用作指针时会退化为指向其第一个元素的指针。
  • @ikegami 比较可能成立,但如果a 是一个数组,a 不等于&amp;aa 是一个数组,可以转换为指向数组的第一个元素的指针。另一方面,&amp;a 是一个指向数组本身的指针。这就是char s[32]; scanf("%31s", &amp;s);不好的原因。
  • @MikeCAT 我知道,它也不是函数。

标签: c function pointers function-pointers implicit-conversion


【解决方案1】:

N1570 6.3.2.1 左值、数组和函数指示符说:

4 函数指示符是具有函数类型的表达式。除了 当它是 sizeof 运算符的操作数时,_Alignof operator,65) 或一元 & 运算符,具有类型的函数指示符 “函数返回类型”被转换为具有 type ‘‘指向函数返回类型的指针’。

这里a*func函数指示符,因为它们具有函数类型。 &amp;a 中的 a 不会转换为指针,因为它是一元 &amp; 运算符的操作数,并且指向函数的指针由 &amp; 运算符检索。 另一方面,func = a; 中的a 根据此规则转换为指向函数的指针。 因此这段代码中的a&amp;a 是等价的。

func(x);中的func也按照这个规则转换为指针。

(*func)(x); 是:

  1. func按照此规则转换为指针
  2. 指针在*func 中被* 取消引用
  3. *func按照这个规则转换成指针

因此(*func)(x); 等价于func(x);

【讨论】:

  • 很好的答案!我只想补充一点,这两个语句在汇编中编译为相同的代码,根据您的解释,这是有道理的,因为它们是等价的。
【解决方案2】:

表达式中使用的函数指示符被隐式转换为指向函数的指针。

例如,您可以像这样调用您的函数

( **********a )( 5 );

也就是说,在这个表达式*a 中,函数指示符a 被转换为指向函数的指针。应用取消引用运算符*,您将再次获得一个函数指示符,该指示符又被转换为指向表达式**a 中的函数的指针。以此类推。

来自 C 标准(6.3.2.1 左值、数组和函数指示符)

4 函数指示符是具有函数类型的表达式。 除非它是 sizeof operator65) 的操作数或一元 & 运算符,类型为“函数返回类型”的函数指示符 转换为具有“函数指针”类型的表达式 返回类型''。

所以在这个作业中

func = &a; // Pointer to a pointer to a function

这里使用了运算符&amp;(参见C 标准中的引用),这意味着函数指示符a 在此表达式中不会转换为函数指针。而且你没有指向函数指针的指针,正如你在上面语句的注释中所写的那样。

【讨论】:

  • 也可以叫( *****&amp;*&amp;***a )( 5 );
【解决方案3】:

根据您提供的文档:

5.6 通过函数指针调用函数 您还可以调用由指针标识的函数。执行此操作时,间接运算符 * 是可选的。

#include <stdio.h>

void foo (int i)
{
  printf ("foo %d!\n", i);
}

void bar (int i)
{
  printf ("%d bar!\n", i);
}

void message (void (*func)(int), int times)
{
  int j;
  for (j=0; j<times; ++j)
    func (j);  /* (*func) (j); would be equivalent. */
}

void example (int want_foo) 
{
  void (*pf)(int) = &bar; /* The & is optional. */
  if (want_foo)
    pf = foo;
  message (pf, 5);
}

所以,The indirection operator * is optional when doing this./* The &amp; is optional. */ cmets 说明了一切。它们是可选的。来自莫斯科的@MikeCat 和@Vlad 解释了为什么它们是可选的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 2017-06-07
    • 2023-03-10
    相关资源
    最近更新 更多