这段代码是什么意思? void(* signal(int sig,void(* func)(int)))(int);
我碰到这段代码,完全没有理解它的含义。
#include <signal.h> void (*signal(int sig, void (*func)(int)))(int);
第二行代码的详细解释是什么?
我知道void
和int
是types,* 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:error:'signal'重新声明为不同types的符号/usr/include/signal.h:93:错误:之前的'signal'声明在这里
TestDeclaration.c:3:error:'signal'重新声明为不同types的符号/usr/include/signal.h:93:错误:之前声明的'signal'在这里
现在我知道这两个审判是不正确的申报方式,但是为什么他们不正确? 为什么原来的申报方式不是重新申报?
它是一个函数的声明,它接受一个int
和一个指向函数的指针(以int
返回void),并返回一个指向函数的指针(以int
和void的forms返回)。
解释或指导解释
你可以把括号中的所有内容都看成一个单一的实体,然后用“声明遵循使用”的规则进行解释。
void (* signal(int sig,void(* func)(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
是一个…
然后,直到find一个无匹配的右括号或声明的结尾: void (* signal
(int sig, void (*func)(int) )(int)
signal
是一个函数,正在返回…
现在,您可以select首先parsing参数,或先返回值。 我会先做返回值。 为此,您往回读取以find匹配的左圆括号: void
( signal( / ... */ ) ) (int)
信号是一个函数,返回一个指针…
来回读这种方式,你会得到连续的阶段:
`signal是一个函数,返回一个指针(函数正在返回…)
`信号是一个函数采取…返回一个指针(函数采取…返回无效)
`信号是一个函数采取…返回一个指针(函数采取一个int和返回void)
`信号是一个函数,它有两个参数:(一个int)和(一个指向函数的指针,它接受一个int并返回void),并返回一个指针给一个函数(函数接受一个int并返回void)
我们来举一个例子来说明这个令人讨厌的声明是如何被使用的:
void (*signal(int sig, void (*func)(int)))(int);
没有太多的冗长,我们可以说“信号”是一个带有两个返回函数的参数的函数。
#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 (ie 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; }
我们来看看会输出什么:
如果颜色= 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 !
如果颜色= 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 !
我多年前创build的一个助记符,这对于理解复杂types是非常宝贵的:
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分层次地构build它。 组件types本身可能是有用的,并且一次只采取一步,使人们不会迷路,试图找出哪个括号匹配哪个。 善待触摸你的代码的下一个人!
如果您发现助记符有用,请随时在其他地方引用它 – 请给我作为其作者的功劳。
顺便说一句,还有“C解释器”工具,它将parsingC的delaractions,并做你的转换为英文说明。 矿被称为CEX,原因很明显,但也有很多其他的存在,如果你不想把这个技巧应用于湿件,或者如果有人给你提供了一些非常难看的东西,你应该能够find一个。
返回指向一个函数的指针,
- 整数作为第一个参数的参数和
- 作为第二个参数的一个函数指针(它接受一个int并返回void)作为参数。
并采取一个整数参数。