在 C 中,作为参数传递时,`&function` 和 `function` 有啥区别?

Posted

技术标签:

【中文标题】在 C 中,作为参数传递时,`&function` 和 `function` 有啥区别?【英文标题】:In C, what is the difference between `&function` and `function` when passed as arguments?在 C 中,作为参数传递时,`&function` 和 `function` 有什么区别? 【发布时间】:2011-09-11 17:06:03 【问题描述】:

例如:

#include <stdio.h>

typedef void (* proto_1)();
typedef void proto_2();

void my_function(int j)
    printf("hello from function. I got %d.\n",j);


void call_arg_1(proto_1 arg)
    arg(5);

void call_arg_2(proto_2 arg)
    arg(5);

void main()
    call_arg_1(&my_function);
    call_arg_1(my_function);
    call_arg_2(&my_function);
    call_arg_2(my_function);

运行这个我得到以下信息:

> tcc -run try.c
hello from function. I got 5.
hello from function. I got 5.
hello from function. I got 5.
hello from function. I got 5.

我的两个问题是:

使用(* proto) 定义的函数原型与未定义的函数原型有什么区别? 使用引用运算符 (&amp;) 和不使用引用运算符调用函数有什么区别?

【问题讨论】:

我认为没有区别。没有发布作为答案,因为我不太确定。 Function pointers in C - address operator "unnecessary" 的可能重复项 【参考方案1】:

没有区别。有关证据,请参阅C99 specification(第 6.7.5.3.8 节)。

“将参数声明为‘函数返回类型’”应调整为“指针指向” 函数返回类型'',如 6.3.2.1。"

【讨论】:

感谢尼克的参考! (顺便说一下,这是第 6.7.**5**.3.8 节。)所以它本质上是一种语言特殊情况? @brice - 谢谢我编辑。是的,一个特例。函数指针 one 对于与语言的其余部分保持一致更有意义,但我猜他们添加了另一种情况以提高可读性 由此得出的结论是,您可以显式取消引用函数名称或函数指针以及任意次数(零、一次或多次)并始终获得相同的结果:***.com/questions/5834520/c-function-pointers/… 这只是事实的一半:6.7.5.3.8 只关心类型声明;函数指示符到函数指针的隐式转换在第 6.3.2.1 节中介绍【参考方案2】:

&amp;functionfunction 作为参数传递时没有区别

但是你的 typedef 是有区别的。我不知道官方的解释,即到底有什么区别,但据我记得

typedef void (*name1)(void);

typedef void(name2)(void);

不同:

name1 是一个指向函数的指针,它不带参数并且不返回任何内容

name2 是一个不带参数且不返回任何内容的函数

你可以通过编译来测试:

typedef void (*pointer)(void);
typedef void (function)(void);

void foo(void)

int main()

    pointer p;
    function f;

    p = foo; //compiles
    p();

    f = foo; //does not compile
    f();

再一次,我不是解释这种行为的确切原因的合适人选,但我相信如果你看一下标准,你会在某处找到解释

【讨论】:

我猜你已经能感觉到这个来了:...当作为争论传递时 - 那么有什么区别呢? :-) 呵呵 :) 不确定,但据我所知完全一样。为什么它们都存在?我不知道。我认为它就像 int & const r;和 int &r; c++的 感谢您对 typedef 的澄清。这是有道理的,并且遵循通常的语义。【参考方案3】:

&function 和 function 之间没有区别——它们都是地址。你可以通过打印它们来看到这一点:

function bar(); 

.... 
printf("addr bar is 0x%d\n", &bar);
printf("bar is 0x%d\n", bar);

【讨论】:

您的答案是正确的,但是“您可以通过...看到这个”是错误的。对于一个数组,array&amp;array 并不完全一样(它们有非常 不同的类型!)但是用printf 打印它们的地址会显示相同的东西(假设你正确使用@ 987654325@ 而不是 %d 并转换为 void *)。顺便说一句,没有办法用 printf 打印函数指针,因为 C 完全没有从函数指针类型到 void * 或任何整数类型的任何转换。 “无法打印函数指针”的说法是不正确的。您可以运行我在上面粘贴的代码(我这样做了)。 该代码通过将不匹配的类型传递给printf 来调用未定义的行为。如果它达到了你的预期,那就意味着你运气不好,即你的代码中的错误没有被发现。 顺便说一句,在十进制数字前打印0x 是相当不正当的... :-) 另外,虽然在 C 语言中数组和 &array 确实不同,但它们编译为相同的值:地址。我认为本着 OP 问题的精神,指出这一点是有帮助的。【参考方案4】:

区别只是风格上的。使用函数指针时,您有相同的场景:

void func (void);

...

void(*func_ptr)(void) = func;

func_ptr();    // call func
(*func_ptr)(); // call func

printf("%d\n", ptr); 
printf("%d\n", *ptr);

有些人说更喜欢 (*func_ptr)() 语法,以明确函数调用是通过函数指针完成的。其他人认为带 * 的样式更清晰。

像往常一样,可能没有科学研究证明任何一种形式都比另一种更好,所以只需选择一种风格并坚持下去。

【讨论】:

以上是关于在 C 中,作为参数传递时,`&function` 和 `function` 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

C 语言指针间接赋值 ( 指针作为 函数参数 的意义 | 间接赋值 代码示例 )

将“const”作为“this”参数传递时出错

将 lambda 作为模板函数参数传递

C语言中,结构体作为函数参数传递,详解?

在 C 中将多维数组作为参数传递

通过引用传递参数