这段代码的含义是什么? void(* signal(int sig,void(* func)(int)))(int);

时间:2010-09-14 06:57:53

标签: c

我遇到了这段代码,完全迷失了解释其含义。

#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);

第2行代码的详细解释是什么?

我知道voidint是类型,* func是函数的指针,括号是优先级。但是我仍然没有把(*信号......),(int)和整个事物结合在一起。越详细越好。

可能我已经知道这个宣言的意义/效果了。但是我不得不做一些试验来帮助我理解发生了什么,如下所示:

  1 #include <signal.h>
  2 void (*signal)(int sig, void (*func)(int));
  3 void (*signal)(int);  // then void (signal)(int) again.
  4 //void (*signal(int sig, void (*func)(int)))(int); //break this line into two lines above
  5
  6 int main(){}

在上面的代码中,我将void (*signal(int sig, void (*func)(int)))(int)分为两行。对于第3行,我尝试了void (*signal)(int)void (signal)(int),但错误结果相同,表明我正在尝试重新声明signal

  

TestDeclaration.c:2:错误:'signal'重新声明为不同类型的符号   /usr/include/signal.h:93:错误:之前的'信号'声明在这里   TestDeclaration.c:3:错误:'signal'重新声明为不同类型的符号   /usr/include/signal.h:93:错误:之前的'信号'声明在这里

现在我知道两种审判都是不正确的申报方式,但为什么它们不正确?为什么原始声明方式不是重新声明?

5 个答案:

答案 0 :(得分:38)

这是一个函数的声明,它接受一个int和一个指向函数的指针(使int返回void)并返回一个指向函数的指针(取int并返回void)


解释或解释指南

您可以通过将括号中的所有内容视为单个实体进行解释,然后使用“声明跟随使用”规则向内工作。

void (* signal(int sig,void(* func)(int)))(int);

括号中的实体看起来像是int并返回void的函数。

剥去外部部分:

*signal(int sig, void (*func)(int))

因此,signal接受一些参数并返回可以取消引用的内容(由于前导*),以形成一个取int并返回void的函数。 / p>

这意味着signal是一个返回指向函数的指针的函数(取int并返回void)。

查看参数需要int(即sig)和void (*func)(int)这是指向函数的指针(转int并返回void )。

答案 1 :(得分:8)

这是复杂的C声明如何变成的经典例子之一 要理解这个声明,引入一个typedef通常会有所帮助:

typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t func);

typedef声明一个指向函数的指针(接受一个int参数并且不返回任何内容)。 函数signal现在可以看作是一个函数,它接受两个参数(一个int和一个指向函数的指针)并返回一个指向函数的指针。

这也可以从原始声明中获得,但需要一些练习。通常的方法是从标识最外层实体的标识符开始(signal就是这种情况):

  

signal是......

然后你向右读,直到你找到一个不匹配的右括号或声明的结尾:void (*signal(int sig, void (*func)(int))(int)

  

signal是一个功能......返回......

现在,您可以选择先解析参数,还是首先解析返回值。我会先做返回值。为此,您向后读取以找到匹配的左括号:void (signal( / ... */ ))(int)

  

`signal是一个函数......返回一个指针......

以这种方式来回读取你会在连续的阶段得到:

  

`signal是一个函数......返回一个指针(函数取......返回...)

     

`signal是一个函数......返回一个指针(函数取......返回void)

     

`signal是一个函数......返回一个指向(函数接受int并返回void)的指针

     

`signal是一个带有两个参数的函数:(一个int)和(一个指向函数的指针获取一个int并返回void),并返回一个指针(函数接受一个int并返回void)

答案 2 :(得分:1)

我多年前创建的助记符,在尝试理解复杂类型时非常有用:

Remember these rules for C declares
And precedence never will be in doubt
Start with the Suffix, Proceed with the Prefix
And read both sets from the inside, out.

当然,除非括号改变了该优先顺序。

将它应用于这种情况:

void (*signal(int sig, void (*func)(int)))(int);

signal is:
  [inside parentheses]
  [suffix ()] a function, whose arguments are
    sig, which is [prefix int] an integer, and
      func, which is:
         [inside parentheses]
           [no suffix within these parens]
           [prefix *] a pointer to
         [suffix ()] a function, whose argument is
           an int
         [no more suffixes]
         [prefix void] and which returns void
         [no more prefixes]
       [no more arguments]
     [prefix *] And which returns a pointer to
     [no more prefixes within these parens]
   [suffix ()] a function, whose argument is
      an int
   [no more suffixes]
   [prefix void] and which returns void.

通过一些练习,你将达到可以动态完成所有这些的程度:

"Signal is function, whose arguments are:
    sig, an integer,
    and func, a pointer to a function whose argument is an int and which returns void
... which returns a pointer to a function that takes int as an argument and returns void.

(抱歉第一次出错 - 我没有练习。)

是的,那个助记符(隐含的“当然除了括号之外)适用于所有C语句,无论指针,数组和函数混合得多么糟糕。

在尝试弄清楚其他人的代码是如何工作的时候,这是一项真正有用的技能......或者甚至可以找出你很久没见过的东西。

但是,是的,处理你认为人们无法一目了然的任何事情的更好方法是使用typedef在图层中构建它。组件类型本身可能很有用,并且一次采取一个步骤可以防止人们迷失,试图弄清楚哪个括号匹配哪个。善待接触你代码的下一个人!

如果您发现助记符很有用,请随时在其他地方引用它 - 请给我作为作者的信誉。

顺便说一句,还有“C Explainer”工具可以解析C版本,并为您转换为英文说明。 Mine被称为CEX,原因显而易见,但是还有很多其他的存在,如果你不想将这种技能用于湿软件,或者如果有人向你提供的东西真的太难以让你跟踪,那么你应该找到一个。

答案 3 :(得分:1)

让我们举一个如何使用这个令人讨厌的声明的例子:

void (*signal(int sig, void (*func)(int)))(int);

没有太多的冗长,我们可以说&#34;信号&#34;是一个带有两个返回函数的参数的函数。

#include <stdio.h>

// First function that could be returned by our principal function
// Note that we can point to it using void (*f)(int)
void car_is_red(int color)
{
    printf("[car_is_red] Color %d (red) is my favorite color too !\n", color);
}

// Second function that could be returned by our principal function
// Note that we can point to it using void (*f)(int)
void car_is_gray(int color)
{
    printf("[car_is_gray] I don't like the color %d (gray) either !\n", color);
}

// The function taken as second parameter by our principal function
// Note that we can point to it using void (*func)(int)
void show_car_type(int mod)
{
    printf("[show_car_type] Our car has the type: %d\n",mod);
}

/* Our principal function. Takes two parameters, returns a function. */
void (* show_car_attributes(int color, void (*func)(int)) )(int)
{
    printf("[show_car_attributes] Our car has the color: %d\n",color); // Use the first parameter

    int mod = 11;  // Some local variable of our function show_car_attributes()
    func(mod);  // Call the function pointed by the second parameter (i.e. show_car_type() )

    // Depending on color value, return the pointer to one of two functions
    // Note that we do NOT use braces with function names
    if (color == 1)
        return car_is_red;
    else
        return car_is_gray;
    }


//main() function
int main()
{
    int color = 2;   // Declare our color for the car
    void (*f)(int);  // Declare a pointer to a function with one parameter (int)

    f = show_car_attributes(color, show_car_type); // f will take the return 
           // value of our principal function. Stated without braces, the 
           // parameter  "show_car_types" is a function pointer of type 
           // void (*func)(int).

    f(color);  // Call function that was returned by show_car_attributes()

    return 0;
}

让我们看看将会输出什么:

如果color = 1

[show_car_attributes] Our car has the color: 1
[show_car_type] Our car has the type: 11
[car_is_red] Color 1 (red) is my favorite color too !

如果color = 2

[show_car_attributes] Our car has the color: 2
[show_car_type] Our car has the type: 11
[car_is_gray] I don't like the color 2 (gray) either !

答案 4 :(得分:0)

返回指向函数的指针 采取:

  • 整数作为第一个参数参数和
  • 指向函数的指针(接受int并返回void)作为参数作为第二个参数。

并采用整数参数。