【问题标题】: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;) 和不使用引用运算符调用函数有什么区别?

【问题讨论】:

标签: c function functional-programming operators


【解决方案1】:

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

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

【讨论】:

  • 感谢尼克的参考! (顺便说一下,这是第 6.7.**5**.3.8 节。)所以它本质上是一种语言特殊情况?
  • @brice - 谢谢我编辑。是的,一个特例。函数指针 one 对于与语言的其余部分保持一致更有意义,但我猜他们添加了另一种情况以提高可读性
  • 由此得出的结论是,您可以显式取消引用函数名称或函数指针以及任意次数(零、一次或多次)并始终获得相同的结果:stackoverflow.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)() 语法,以明确函数调用是通过函数指针完成的。其他人认为带 * 的样式更清晰。

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

【讨论】:

    猜你喜欢
    • 2015-08-10
    • 2012-07-12
    • 1970-01-01
    • 2017-12-05
    • 2015-03-08
    • 2012-02-18
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多