我遇到了这段代码,完全迷失了解释其含义。
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
第2行代码的详细解释是什么?
我知道void
和int
是类型,* 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:错误:之前的'信号'声明在这里
现在我知道两种审判都是不正确的申报方式,但为什么它们不正确?为什么原始声明方式不是重新声明?
答案 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)
返回指向函数的指针 采取:
并采用整数参数。