为什么似乎func与C中的&func相同?

问题描述

根据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

例如,我确定&foo&&foo不同,因此为什么在 func相同的情况下为什么为&func

解决方法

N1570 6.3.2.1左值,数组和函数指示符表示:

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

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

func中的func(x);也会根据此规则转换为指针。

(*func)(x);是:

  1. func根据此规则转换为指针
  2. *中的*func取消了指针的引用
  3. *func根据此规则转换为指针

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

,

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

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

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

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

根据C标准(6.3.2.1左值,数组和函数指示符)

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

所以在这项作业中

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

使用了运算符&(请参见C标准的引用),这意味着函数标识符a不会在此表达式中转换为函数指针。而且,您没有指向上述语句的注释中所写的函数指针。

,

根据您提供的文档:

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 & is optional. */的评论说明了一切。它们是可选。来自莫斯科的@MikeCat和@Vlad解释了为什么它们是可选的