【问题标题】:type of function pointer函数指针的类型
【发布时间】:2015-01-05 19:35:04
【问题描述】:

我有一个简短的程序来测试“无限递归”。但是,我遇到了另一个与函数指针相关的棘手问题......

程序如下:

#include <stdio.h>

int repeat(char (*func)(int, int), int a) {
  func(a, a+1);
  return repeat(func, a+1);
}

char f (int a , int b){
  printf("%d\n", a);
  //return (double)(a + b);
  return 'c';
}

int main(int argc, char const *argv[])
{
  repeat(&f, 1);
  return 0;
}

就我而言,我认为“repeat(&f, 1)”中的'f'具有“char *”的类型和'func' “int repeat(char (*func)(int, int), int a)”的类型也是“char *”。

然而,这似乎很奇怪。如果我将“(char (*func)(int, int), int a)”更改为 “(char func(int, int), int a) ”,编译器(在gcc和vc6中测试)没有任何警告,运行结果是一样的。

如果我将“(char (*func)(int, int), int a) ”更改为“(double func(int, int), int a) ”, 编译器抛出:

警告:不兼容的指针类型将 'char ()(int, int)' 传递给 'double ()(int, int)' 类型的参数 [-Wincompatible-pointer-types ] 重复(&f, 1);

似乎编译器将“double (int, int)”和“double (*)(int, int)”视为相同的东西。换句话说,如果我将“(char (*func)(int, int), int a)”更改为“double (*func)(int, int) ”,编译器会抛出同样的信息(我已经测试过了):

警告:不兼容的指针类型将 'char ()(int, int)' 传递给 'double ()(int, int)' 类型的参数 [-Wincompatible-pointer-types ] 重复(&f, 1);

上帝... 好吧,这不是结束。 之后,我将“repeat(&f, 1)改为“repeat(f, 1)”,其他部分不变。 也就是说,整个程序是:

#include <stdio.h>

int repeat(char (*func)(int, int), int a) {
  func(a, a+1);
  return repeat(func, a+1);
}

char f (int a , int b){
  printf("%d\n", a);
  //return (double)(a + b);
  return 'c';
}

int main(int argc, char const *argv[])
{
  repeat(f, 1);
  return 0;
}

编译器不给出任何警告,运行结果是一样的。

所以我很困惑,以下所有巴黎都没有产生警告和正确的结果。

    1   repeat(&f, 1)   int repeat(char (*func)(int, int), int a)
    2   repeat(&f, 1)   int repeat(char func(int, int), int a) 
    3   repeat(f, 1)    int repeat(char (*func)(int, int), int a) 
    4   repeat(f, 1)    int repeat(char func(int, int), int a) 

当然,“repeat(f, 1)”中的“f”的类型是“char (int, int)”,而“func”在“int repeat(double (func)(int, int), int a)”中的类型为“char ()(int, int)”。

您可以通过将“int repeat(char (*func)(int, int), int a)”更改为“int repeat(double (*func)(int , int), int a)”并查看警告信息:

警告:不兼容的指针类型将 'char (int, int)' 传递给 'double ()(int, int)' 类型的参数 [-Wincompatible-pointer-types] repeat(f, 1);*

谁能给一些cmets?我完全认为关于类型,只有四个中的第一个是正确的。

【问题讨论】:

  • 这段代码中没有任何char *char (*)(int, int) 是一个指向函数的指针,它返回一个 char 并接受两个 int 参数。另外,cdecl.org.
  • C function pointer syntax的可能重复
  • 请注意,C 的类型系统不能声明一个接受自己作为函数参数的非可变函数。

标签: c pointers function-pointers


【解决方案1】:

当用作函数参数时,两种语法

foo(char bar(int, int), int a)  

foo(char (*bar)(int, int), int a)

从编译器的角度来看是相同的。

还请注意,当您调用函数foo 时,传递给它的函数名称将被视为指向该函数的指针。这两个调用都是有效的

foo(&f, 1)
foo(f, 1)

就我而言,我认为repeat(&amp;f, 1) 中的f 具有char * 的类型,int repeat(char (*func)(int, int), int a) 中的func 也具有char * 的类型。

没有。 ffunc 都是char (*)(int, int) 类型,即它们是指向一个函数的指针,该函数接受两个int 作为参数并返回char

【讨论】:

  • 谢谢!下班回家后得到了答案……其实应该是一样的吧! (Christophe 的回答似乎更完整,所以我投票给他,你已经有 33.2k 的名声了:)你这个极客。)
  • “f 和 func 都是 char ()(int, int) 类型,即它们是指向以两个 int 作为参数并返回 char 的函数的指针”。再次感谢你。类型确实是 char ()(int, int) 。我犯了一个愚蠢的错误。
【解决方案2】:

参数类型:

() 在语法中强加的优先顺序:

    int repeat(char (*func)(int, int), int a)

表示(*func)(int,int) 是一个函数,它接受两个int 参数并返回一个char* 表示func 是一个指向返回char 的函数的指针。

以下更现代的语法也可以:

    int repeat(char func(int, int), int a)

注意,以下看起来与第一个很接近,但完全不同,函数参数将是一个指向返回 char * 的函数的指针:

    int repeat(char *func(int, int), int a)

是的,为了完整起见,int repeat((char *)func(int, int), int a) 将是一个语法错误,因为(char*) 将被理解为强制类型转换运算符,而应该是类型。

使用 f 和 &f 语法:

C11 标准第 6.5.3.2 节规定“一元 &amp; 运算符产生其操作数的地址。如果操作数的类型为 ''type'',则结果为type ''指针类型''":

  • f 是一个以两个 int 作为参数并返回一个 char 的函数
  • 所以&amp;f 是一个指向以两个int 作为参数并返回一个char 的函数的指针。

但第 6.3.2.1/4 节中的标准还指出“函数指示符是具有函数类型的表达式。(...) 类型为“函数返回类型”的函数指示符被转换到具有类型“指向函数返回类型的指针”的表达式”:

  • f 是一个以两个 int 作为参数并返回一个 char 的函数
  • 如果在表达式中提供(当然不是在函数调用的语法中),f 也被理解为指向以两个int 作为参数并返回一个char 的函数的指针。

现在,您会发现这两种语法。

从历史上看,以前在(*func)() 语法中使用* 是强制调用指向的函数的(参见原始K&R)。

【讨论】:

  • 非常感谢,您竟然对C标准/C11标准了解这么多,真是令人惊讶。真的很酷。那么,它们在过去是不同的,但现在是一样的?
  • 也许这就是主流语言发展的方式?出现了新的语法,但由于庞大的代码库,旧的语法被保留了下来。然后是口味问题:有些人会更喜欢extern char rpt(char(*)(int, int));,有些人会更喜欢extern char rpt(char(int, int));
  • 大部分是一个不错的答案,但你的最后一句话是不准确的。我有我的 K&R 第 1 版副本,它涵盖了指向 pp114-117 上的函数的指针。用作函数指针的函数名称中没有一个以&amp; 开头;这在当时是不合法的(但在 C89 之后才合法,这本书写成时还有十多年的时间)。此外,在 K&R 1 中,调用指向函数的指针的唯一方法是 (*pointer_to_func)(arg1, arg2);同样,标准 C 允许使用简写 pointer_to_func(arg1, arg2)
  • 请注意 use-mimics-type 如何在(*func)(a1, a2) 中应用,它与int (*func)(int a1, int a2) 之类的声明相匹配,int (*func)(int a1, int a2) 告诉编译器(*func)(a1, a2) 的返回类型是int。新符号有一些优点,但您无法确定some_name(a1, a2) 是否是函数的调用,例如int some_name(int a1, int a2) 或函数指针(可能来自函数参数列表)int (*some_name)(int a1, int a2)。使用旧系统,一目了然;用新的,没那么多。
  • @ZirunZhu:是否更清晰取决于您的观点。当我学习 C 时,函数名称上的 &amp; 不是 AFAICR 的选项,而且您从未在数组名称前写 &amp;,因为不同的 C 编译器对它的解释不同。这是标准修复的一个模糊区域。很多 C 都在“类型模仿使用”上工作。当你写int *ip;时,表示如果你后续使用*ip,则类型为int。与函数指针类似:如果您声明int (*func)(int a1, int a2),则(*func)(1, 2) 会生成int。这些天,你也可以写func(1, 2)
猜你喜欢
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多