37

考虑以下 typedef:

typedef int (*f1)(float);
typedef f1 (*f2)(double);
typedef f2 (*f3)(int);

f2是一个返回函数指针的函数。与 相同f3,但函数的类型,即f3返回的指针,是f2。如何在f3没有 typedef 的情况下定义?我知道 typedefs 是更简洁、更容易理解的定义方式f3。但是,我的目的是更好地理解 C 语法。

4

7 回答 7

137

从您的声明开始f1

int (*f1)(float);

你想f2成为一个返回函数的指针f1,所以f1在上面的声明中替换为f2

int (*      f1     )(float);
            |
      +-----+-----+
      |           |
      v           v
int (*(*f2)(double))(float);

声明内容如下

        f2                   -- f2
       *f2                   -- is a pointer
      (*f2)(      )          -- to a function
      (*f2)(double)          --   taking a double parameter
     *(*f2)(double)          --   returning a pointer
    (*(*f2)(double))(     )  --   to a function
    (*(*f2)(double))(float)  --     taking a float parameter
int (*(*f2)(double))(float)  --     returning int

您重复该过程f3

int (*(*    f2    )(double))(float);
            |
        +---+----+
        |        |
        v        v
int (*(*(*f3)(int))(double))(float);

读作

          f3                           -- f3
         *f3                           -- is a pointer
        (*f3)(   )                     -- to a function
        (*f3)(int)                     --   taking an int parameter
       *(*f3)(int)                     --   returning a pointer
      (*(*f3)(int))(      )            --   to a function
      (*(*f3)(int))(double)            --     taking a double parameter
     *(*(*f3)(int))(double)            --     returning a pointer
    (*(*(*f3)(int))(double))(     )    --     to a function
    (*(*(*f3)(int))(double))(float)    --       taking a float parameter
int (*(*(*f3)(int))(double))(float);   --       returning int
于 2012-05-25T18:07:35.793 回答
14

在 C++ 中,模板的奇迹可以使这变得更容易一些。

#include <type_traits>

std::add_pointer<
    std::add_pointer<
        std::add_pointer<
            int(float)
        >::type(double)
    >::type(int)
>::type wow;
于 2012-05-25T17:30:56.977 回答
7

与 typedef 相同,只是您将函数定义放在其名称的位置。

如下f2所示:

typedef int (*(*f2)(double))(float);

你可以做f3一个练习,因为我假设这是家庭作业;)

于 2012-05-25T17:26:19.110 回答
6

只是不要。可以做到,但是会很混乱。Typedef 可以方便地编写和阅读这段简短的代码。

f不带参数并返回函数指针的函数可能int (*)(float)类似于(未经测试):

int (*f())(float);

然后剩下的你只需要继续添加括号,直到它看起来像 lisp。

于 2012-05-25T17:32:50.463 回答
4

学习左右规则

“左右”规则是解读 C 声明的完全常规规则。它在创建它们时也很有用。

于 2013-08-16T09:05:52.173 回答
0

使用std::function

typedef std::function<int(float)> f1;
typedef std::function<f1(double)> f2;
typedef std::function<f2(int)>    f3;

或者

typedef std::function<std::function<std::function<int(float)>(double)>(int)> f3;
于 2012-06-01T17:38:46.057 回答
0

受 John Bode 回答的启发,我想以图形方式呈现它。它应该可以帮助您了解编译器如何将其转换为 AST:

函数返回值中的函数,递归

我们首先 (1) 从压缩类型 f3 开始,如“typedef f2 (*f3)(int);”所示。它本身就是一个函数类型。然后在 (2) 中将其进一步解包,其中放置了封闭的花括号,实质上执行 C 语言的“is-function”CFG 生成(我假设读者对编程语言词法分析有一个基本概念)。通过查看 (3),您会看到我们已经递归执行了三次“is-function”词法分析步骤,图中的“函数”节点可以看到这三次。

在自定义符号中尝试所需(但简化)的 CFG 产品,它们看起来像......

declaration -> underlying_type:specifier sp ( func-ptr-decl | specifier )
func-ptr-decl -> '(' sp '*' sp ( func-ptr-decl | specifier ) sp ')' sp '(' sp param-list sp ')'

说明符是一个字符串,在 C 编程语言中最好解释为变量名,sp 是可选的空格字符串,param-list 被简化为(可能为空)逗号分隔的声明列表。

在 C 中,每条引入变量或参数的语句都称为声明。声明由位置/名称、数据类型和初始化程序组成。在给定的问题中,我们有类型是指向函数的声明。函数指针类型递归嵌套最多 3 次。该图以箭头指向类型的方式显示了它,这意味着它们嵌套在其他类型中。

于 2021-11-24T21:23:53.570 回答