繁体   English   中英

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

[英]What's the meaning of this piece of code? void (*signal(int sig, void (*func)(int)))(int);

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

#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:错误:'信号'重新声明为不同类型的符号/usr/include/signal.h:93:错误:之前'信号'的声明在这里
TestDeclaration.c:3:错误:'signal'重新声明为不同类型的符号/usr/include/signal.h:93:错误:之前'signal'的声明在这里

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

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


解释或解释指南

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

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

括号中的实体看起来像一个采用int并返回void的函数。

剥去外部部分:

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

因此, signal接受一些参数并返回可以被解除引用的东西(由于前导* )以形成一个接受int并返回void的函数。

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

查看参数,它采用int (即sig )和void (*func)(int) ,它是一个指向函数的指针(取int并返回void )。

这是复杂的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) void ( signal( / ... */ ) ) (int)

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

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

`signal是一个函数...返回一个指向a的函数(函数正在......返回......)

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

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

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

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

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解释器”工具,它将解析C解体并为您转换为英文描述。 Mine被称为CEX,原因显而易见,但是还有很多其他的存在,如果你不想将这种技能用于湿软件,或者如果有人向你提供的东西真的太难以让你跟踪,那么你应该找到一个。

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

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

没有太多冗长,我们可以说“signal”是一个带有两个返回函数的参数的函数。

#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 !

返回指向一个函数的指针:

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

并采用整数参数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM