(注意:链接另一个显示函数指针示例的答案无济于事。我的问题恰恰是关于不同答案中显示的多种方式,并试图理解它们之间的差异)
我试图了解将函数作为参数传递给C中另一个函数的正确方法(无C ++)。我已经看到了几种不同的方式,但对我而言,区别尚不明确。
我正在运行macOS
我的编译器是GCC:
$ gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
我在我的Makefile中使用CFLAGS=-Wall -g -O0
。
以下4个片段均产生相同的结果(至少具有相同的可见输出)。请注意,样本之间的唯一区别在于声明和execute
函数的调用。我已经在引号中包括了我最初将这些示例中的每个示例称为只是为了区分它们的方式(因此命名可能是错误的)。
它们实际上只是以下四个排列的全部:
execute
以接收void f()
或void (*f)()
execute
或execute(print)
调用功能execute(&print)
请注意,在所有情况下,均使用f()
而不是(*f)()
调用该函数。 但是我也用(*f)()
进行了测试,得出了相同的结果。所以8个排列,实际上(为简洁起见,这里仅显示4个)
片段1:“传递without指针,接收without指针”
#include <stdio.h>
void execute(void f()) {
printf("2 %p %lu\n", f, sizeof(f));
f();
}
void print() {
printf("Hello!\n");
}
int main() {
printf("1 %p %lu\n", print, sizeof(print));
execute(print);
return 0;
}
片段2:“传递with指针,并接收with指针”
#include <stdio.h>
void execute(void (*f)()) {
printf("2 %p %lu\n", f, sizeof(f));
f();
}
void print() {
printf("Hello!\n");
}
int main() {
printf("1 %p %lu\n", print, sizeof(print));
execute(&print);
return 0;
}
片段3:“传递with指针,并接收without指针”
#include <stdio.h>
void execute(void (f)()) {
printf("2 %p %lu\n", f, sizeof(f));
f();
}
void print() {
printf("Hello!\n");
}
int main() {
printf("1 %p %lu\n", print, sizeof(print));
execute(&print);
return 0;
}
片段4:“传递without指针,并接收with指针”
#include <stdio.h>
void execute(void (*f)()) {
printf("2 %p %lu\n", f, sizeof(f));
f();
}
void print() {
printf("Hello!\n");
}
int main() {
printf("1 %p %lu\n", print, sizeof(print));
execute(print);
return 0;
}
对于所有示例:
Hello
正确打印%p
中打印的值在第一和第二打印中都相同sizeof
在第一次打印中始终为1sizeof
在第二次打印中始终为8我已经阅读了几个示例(Wikipedia,StackOverflow,以及StackOverflow答案中链接的其他资源),其中很多显示了不同的示例。 我的提问正是为了理解那些差异。
[Wikipedia article about function pointers显示了类似于代码段4的示例(由我简化):
#include <math.h>
#include <stdio.h>
double compute_sum(double (*funcp)(double), double lo, double hi) {
// ... more code
double y = funcp(x);
// ... more code
}
int main(void) {
compute_sum(sin, 0.0, 1.0);
compute_sum(cos, 0.0, 1.0);
return 0;
}
注意:
compute_sum(sin, 0.0, 1.0)
传递([无 &
上的sin
)]double (*funcp)(double)
(with *
)funcp(x)
(without *
,因此没有(*funcp)(x)
)同一Wikipedia文章中的后续示例告诉我们,不需要传递函数时的&
,无需任何进一步说明:
// This declares 'F', a function that accepts a 'char' and returns an 'int'. Definition is elsewhere.
int F(char c);
// This defines 'Fn', a type of function that accepts a 'char' and returns an 'int'.
typedef int Fn(char c);
// This defines 'fn', a variable of type pointer-to-'Fn', and assigns the address of 'F' to it.
Fn *fn = &F; // Note '&' not required - but it highlights what is being done.
// ... more code
// This defines 'Call', a function that accepts a pointer-to-'Fn', calls it, and returns the result
int Call(Fn *fn, char c) {
return fn(c);
} // Call(fn, c)
// This calls function 'Call', passing in 'F' and assigning the result to 'call'
int call = Call(&F, 'A'); // Again, '&' is not required
// ... more code
注意:
Call(&F, 'A')
传递(with &
上的F
)Fn *fn
(with *
)fn(c)
(without (*fn)
)func(print)
传递([无 &
上的print
)]void (*f)(int)
(with *
)(*f)(ctr)
调用(with (*fn)
)This answer显示2个示例:
execute(print)
传递(without &
)void f()
(无 *
)f()
(without *
)execute(&print)
传递(with &
)void (*f)()
(with *
)f()
(without *
)&
的示例]int (*functionPtr)(int, int)
(with *
)(*functionPtr)(2, 3)
调用(with *
)This linked material I found in one of the answers(实际上是C ++,但是不使用任何C ++特定于函数指针的东西):
&Minus
传递(with &
)float (*pt2Func)(float, float)
(with *
)pt2Func(a, b)
(without *
)我在这里提供了7个示例,这些示例在传递函数作为参数/接收函数作为参数/调用作为参数接收的函数时,提供了使用或不使用&
和*
的至少5种组合。
[我相信上一节表明,关于StackOverflow和我链接的其他材料(大多数链接在StackOverflow的答案中)中最相关的问题/答案尚未达成共识。
似乎所有这四种方式都由编译器完全相同地处理,或者在如此简单的示例中没有出现非常细微的差异。
我理解为什么第二张打印在代码段2和4中将sizeof(f)
打印为8
。这就是我的64位系统中的指针大小)。但是我不明白为什么即使在execute
函数声明不带*
的参数的情况下,第二张打印也会打印指针的大小(代码段1和3),并且我也不明白为什么在第一张打印中函数变量的sizeof
等于1
。
f(myFunc)
并实际使用f(&myFunc)
,或类似的东西。我想知道哪种是“规范”方式。f()
或(*f)()
调用通过参数接收的传递函数?sizeof(print)
)的大小始终为1
?在这种情况下,我们实际得到的sizeof是多少? (显然不是指针的大小,在我的64位计算机上为8字节。如果使用sizeof(&print)
,则将获得指针的大小。)>sizeof(f)
,void (f)()
也给我8(指针的大小)(因此,如果没有*
,我可以假设它是不是指针)。((请回答时,请尝试按编号的问题中断答案)
((注:链接显示函数指针示例的另一个答案是没有帮助的。我的问题恰恰是关于不同答案中显示的多种方式,并试图理解...的问题]
我的4个摘要之间是否存在实际差异?为什么它们的行为都完全相同?