【问题标题】:Function pointers and address of a function函数指针和函数地址
【发布时间】:2012-03-22 02:23:09
【问题描述】:

所以我想在制作函数指针时,你不需要operator & 来获取初始函数的地址:

#include <stdio.h>

double foo (double x){
    return x*x;
}

int main () {

    double (*fun1)(double) = &foo;
    double (*fun2)(double) =  foo;

    printf("%f\n",fun1(10));
    printf("%f\n",fun2(10));

    printf("fun1 = %p \t &foo = %p\n",fun1, &foo);
    printf("fun2 = %p \t  foo = %p\n",fun2,  foo);       

    int a[10];

    printf("  a = %p \n &a = %p  \n",a,&a);

    return 0;
}

输出:

>./a.out 
100.000000
100.000000
fun1 = 0x4004f4      &foo = 0x4004f4
fun2 = 0x4004f4       foo = 0x4004f4
  a = 0x7fff26804470 
 &a = 0x7fff26804470 

然后我意识到数组也是如此,这意味着如果您有 int a[10] 两个 a&amp;a 指向同一个位置。为什么是数组和函数?该地址是否保存在与保存在其中的值(地址)具有相同地址的内存位置?

【问题讨论】:

  • 我一直不太明白为什么您不必使用 address-of 运算符来获取函数的地址。我一直认为这只是一点语法糖。
  • @Bill:没错!这就是我一直以来的想法,但似乎你不需要!
  • 如果地址和自己保存在同一个内存位置,就不可能有实际的功能码/数组数据!您实际上会将数组视为指针,将作为参数传递的函数也视为指针,因此您不需要 addressof 运算符。基本上,函数或数组的“值”是无稽之谈。只有地址是有意义的,所以当你查询“值”时,你会得到它,当你查询地址时也是如此。

标签: c function pointers function-pointers


【解决方案1】:

给定int a[10]a&amp;a 产生相同的地址,是的,但它们的类型不同。

a 的类型为 int[10]。当它被隐式转换为指针类型时,指针的类型为int*,并指向数组的初始元素。 &amp;a 的类型为 int (*)[10](即指向十个整数数组的指针)。因为数组中不能有填充,所以它们都产生具有相同的指针,但指针具有不同的类型

函数类似于数组,但不完全相同。您的函数foo 的类型为double(double)。每当foo 在表达式中使用并且不是一元&amp; 运算符的操作数时,它就会隐式转换为指向自身的指针,该指针的类型为double(*)(double)

因此,出于所有实际目的,函数的名称和指向同一函数的指针是可以互换的。有一些微妙之处,我在回答 "Why do all these crazy function pointer definitions all work? What is really going on?" 时讨论了所有这些问题(这个问题是关于 C++ 的,但 C++ 中非成员函数的规则与 C 中的函数相同。)

【讨论】:

    【解决方案2】:

    不,没有专门用于指向函数/数组的额外存储空间。

    对于大多数变量variable_name具有获取该变量地址以外的含义,因此您需要使用&amp;variable来获取地址。

    对于函数或数组,function_name(本身,不带括号)没有任何其他含义,因此将其解释为获取函数的地址没有问题。

    反之亦然:普通指针需要显式取消引用,但指向函数的指针不需要(同样,因为没有其他合理的解释),所以给定一个指向函数的指针,如下所示:

    int (*func)(param_list);
    

    以下是等价的——两者都调用func指向的任何函数:

    (*func)(params);
    
    func(params);
    

    【讨论】:

    • 这似乎有点不同,对于 int a[10],(*a)[5] 不是一个有效的调用
    【解决方案3】:

    fun&amp;fun 完全相同(除了 sizeof(f) 是非法的)。 a&amp;a 与指针算法相同:a + 10 == &amp;a + 1,因为 10*sizeof(*a) == sizeof(a)(其中 sizeof(*a) == sizeof(int))。

    【讨论】:

      【解决方案4】:

      基本上,由于函数名“已知”为函数,因此 & 并不是绝对必要的。这种行为与数组相同。回想一下,函数本身不是变量,因此它的行为有时与您预期的略有不同。如果你有 K&R 的第 2 版,你可以查看第 5.11 节关于函数的指针,或者最后的参考手册,

      第 A7.1 节指针生成:如果表达式的类型或 对于某些类型 T,子表达式是“T 的数组”,那么 表达式是指向数组中第一个对象的指针,类型 的表达式被更改为“指向 T 的指针”。这种转换确实 不取代表达式的是一元 & 的操作数 运算符,... 类似地,“函数返回 T”类型的表达式 除非用作 & 运算符的操作数,否则将转换为 “指向返回 T 的函数的指针。”

      第 A7.4.2 节地址运算符:一元 & 运算符获取地址 它的操作数....结果是指向对象或函数的指针 由左值引用。如果操作数的类型是 T,则类型 结果是“指向 T 的指针”。

      据我所知,C99 也是如此。

      【讨论】:

        【解决方案5】:

        printf("fun1 = %p \t &foo = %p\n",fun1, foo);

        在这里,您通过使用 pass by value 传递函数指针来调用 foo

        printf("fun2 = %p \t foo = %p\n",fun2, &foo)

        在这里,您通过使用 pass by reference 传递函数指针来调用 &amp;foo

        在这两种情况下,您都只使用函数指针调用printf

        记住foo 本身是function pointer value 并且`不是变量。

        数组也是如此。 int arr[10] 转换为获取 10 个整数的连续块,并将第一个元素的地址存储到 arr 中。所以 arr 也是一个指针。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多