函数指针的类型

时间:2014-11-09 11:53:13

标签: c pointers function-pointers

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

该计划如下:

#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;
}

至于我,我认为“重复(&amp; f,1)”中的'f'具有“ char * ”的类型和'func' 'in“ int repeat(char(* func)(int,int),int a)”的类型为“ char * ”。

然而,这似乎很奇怪。如果我改变“(char(* func)(int,int),int a)”to “(char func(int,int),int a)”,编译器(在gcc和vc6中测试)不会发出任何警告,并且运行结果是相同的。

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

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

神... 好吧,这不是结束。 之后,我将“重复(&amp; f,1)更改为“重复(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) 

当然“重复(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); *

谁可以发表评论?我完全认为只有四个中的第一个在类型方面是正确的。

2 个答案:

答案 0 :(得分:3)

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

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

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

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

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

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

至于我,我认为f中的repeat(&f, 1)类型为char *,而func中的int repeat(char (*func)(int, int), int a)类型为char * }},太。

不。 ffunc都属于char (*)(int, int)类型,即它们是 指向函数的指针,该函数将两个int作为参数并返回{{1} }

答案 1 :(得分:1)

参数类型:

()在语法:

中强加的优先顺序
    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和&amp; f语法:

C11标准部分6.5.3.2声明“一元&运算符产生其操作数的地址。如果操作数的类型为''type'',则结果有类型''指向类型''“的指针:

  • f是一个函数,将两个int作为参数并返回char
  • 所以&f是指向函数的指针,该函数将两个int作为参数并返回char

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

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

如今,你会发现两种语法。

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