“typedef int (f)(void)”这样带括号的typedef是什么意思?它是函数原型吗?

36
typedef int (fc_name) (void);

这里的fc_name是任何有效的C符号。

与函数指针typedef相比,它有什么不同吗?

6个回答

40

这是一个指向函数类型的typedef。其目的是用于函数指针,但在这种情况下,使用它的语法应该是:

int bar(void);

fc_name* foo = bar; /* Note the * */

更新: 如Jonathan Leffler的答案中所述,typedef关键字可以用于声明函数。其中一个用途是声明一组回调函数:

typedef int (callback)(int, void*);

callback onFoo;
callback onBar;
callback onBaz;
callback onQux;

+1:啊 - 原来是这样才有用!你向我展示后,我才证明你是正确的。我们活着就要学习;SO(Stack Overflow)很棒。 - Jonathan Leffler
我想你仍然需要为每个函数定义包含整个函数原型吗?编辑:不用了,Jonathan Leffler的答案已经解决了这个问题。 - Hubro

23
第一个括号是多余的-它与以下内容等效:
typedef int fc_name(void);

我认为这并没有什么实用价值,尽管我不能让GCC单独抱怨它。

这意味着fc_name是一个函数类型的别名,它不带参数并返回一个int。直接使用起来并不是很有用,但是你可以使用如下方式声明rand()函数:

fc_name rand;

你不能在函数定义中使用typedef
指向函数的typedef应该这样写:
typedef int (*fc_name)(void);

这段代码表明没有星号的typedef不是函数指针(参考一个现已删除的答案):
static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1 x = function;
fc_name2 y = function;
fc_name3 z = function;

当编译时,'gcc' 会说:

gcc -Wextra -Wall -pedantic -c -O x.c
x.c:10:1: error: function ‘x’ is initialized like a variable
x.c:11:1: error: function ‘y’ is initialized like a variable

以下代码演示了你确实可以像jamesdlin建议的那样使用fc_name *var = funcname;

static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1  x_0 = function;
fc_name1 *x_1 = function;
fc_name2  y_0 = function;    // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function;    // Damn Bessel functions - and no <math.h>
fc_name3  z   = function;

使用y0,y1会生成GCC警告:
x.c:12:11: warning: conflicting types for built-in function ‘y0’
x.c:13:11: warning: built-in function ‘y1’ declared as non-function

另外,基于 schot 的评论:

static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1  x_0 = function;   // Error
fc_name1 *x_1 = function;   // x_1 is a pointer to function
fc_name1  x_2;              // Declare int x_2(void);
fc_name1 *x_3 = x_2;        // Declare x_3 initialized with x_2

fc_name2  y_0 = function;   // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function;   // Damn Bessel functions - and no <math.h>
fc_name1  y_2;              // Declare int y_2(void);
fc_name1 *y_3 = x_2;        // Declare y_3 initialized with y_2

fc_name3  z   = function;

很有趣 - C语言的黑暗角落确实很模糊。


1
有些人更喜欢typedef在函数签名中,而不是指针传递前。这将把指针传递的“明确性”转移到每个函数指针的声明中。我认为这只是一种风格问题。 - detly
5
您可以使用函数类型定义来进行函数 声明(原型),但不能用于函数 定义。但这并不是非常有用,除了混淆之外。 - schot
1
@schot:很好,我不知道它可以用于函数声明。实际上,我认为这对于声明一组回调函数是有用的;以前我使用预处理器宏来简化它。 - jamesdlin

2
  1 #include <stdio.h>
  2 
  3 
  4 typedef int (fc_name)(void);
  5 
  6 
  7 
  8 int test_func1 ()
  9 {
 10     printf("\n test_func1 called\n");
 11 
 12     return 0;
 13 }
 14 
 15 int test_func2 (void)
 16 {
 17     printf("\n test_func2 called\n");
 18     return 0;
 19 }
 20 
 21 int handler_func(fc_name *fptr)
 22 {
 23     //Call the actual function
 24     fptr();
 25 }
 26 
 27 int main(void)
 28 {
 29     fc_name  *f1, *f2;
 30 
 31     f1 = test_func1;
 32     f2 = test_func2;
 33 
 34     handler_func(f1);
 35     handler_func(f2);
 36 
 37     printf("\n test complete\n");
 38 
 39     return 0;
 40 }

输出:

 test_func1 called

 test_func2 called

 test complete

我曾经质疑的typedef(这里是第4行),代表了一个函数类型,不同于函数指针typedef。这种typedef并没有太大意义。它们被用作样式标准或者有意制造混淆。


请注意,您可以使用以下代码:int handler_func2(fc_name fptr) { return fptr(); } 因为“function”参数会自动被视为(转换为)函数指针。 - Jonathan Leffler

1
我之前从未见过将括号用于typedef名称,但是在函数名周围使用括号有助于防止其被扩展为同名的函数式宏。例如,在ctype.h中,isxxx函数被定义为函数和宏。这样你就可以取一个指向isalpha的指针。但是C库如何定义不在同一行的isalpha呢?可能像这样:
#include <ctype.h>

int
(isalpha)(int c)
{
    return isalpha(c);
}

在函数体中使用的isalpha被扩展为宏,而在函数头中使用则不是。

1
有趣!typedef声明是一个带有typedef作为存储类的声明。
typedef int   fc_name1 (void);   
// this defines a function type called fc_name1 
// which takes no parameter and returns int

稍后,您可以定义以下函数:
fc_name1 myFunc;
// this is equivalent to the next line
// int myFunc(void);

你应该能够从C/C++标准中找到答案!

0

正确的形式是:

typedef int (*myfunc)(void);

你可以像下面这样定义一个函数:
int helloword(void) {
    printf("hello, world\n");
}

然后定义一个指向这个函数的变量:

myfunc hw_func;
hw_func = helloworld;

通过函数指针调用函数:

int ret = (*hw_func)();

我们需要函数指针的原因是C语言没有预定义的函数指针,而在C语言中使用void*指针调用函数是非法的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接