【问题标题】:The reason behind function pointer being the function name itself in c language?函数指针背后的原因是c语言中的函数名本身?
【发布时间】:2020-02-27 06:45:31
【问题描述】:

已经有一堆相关问题如

Function pointers and address of a function

Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?

但我很好奇为什么会这样的原因,而不是简单地记住所有这些规则。

下面是一个简单的C代码sn-p和对应的arm汇编代码:

int foo() {
    return 42;
}

int main() {
    int (*bar)() = foo; // same assembly code if swapping with '&foo' 
    int a, *b;
    a = foo();
    *b = bar();
}

foo:
        str     fp, [sp, #-4]!
        add     fp, sp, #0
        mov     r3, #42
        mov     r0, r3
        add     sp, fp, #0
        ldr     fp, [sp], #4
        bx      lr
main:
        push    {fp, lr}
        add     fp, sp, #4
        sub     sp, sp, #16
        ldr     r3, .L5
        str     r3, [fp, #-8]
        bl      foo
        str     r0, [fp, #-12]
        ldr     r3, [fp, #-8]
        blx     r3
        mov     r2, r0
        ldr     r3, [fp, #-16]
        str     r2, [r3]
        mov     r3, #0
        mov     r0, r3
        sub     sp, fp, #4
        pop     {fp, pc}
.L5:
        .word   foo

ldr r3, .L5 中可以看到,函数名称显示为一个标签,相当于代码块的地址,如果我将foo&foo 交换,汇编代码仍然是相同的,因为@987654328 @ 没有存储地址。但是指针b 和它指向的值有它们的专用存储。因此,不区分foo&foo 是合理的,但对于b*b 是必要的。

但是,我找不到任何可靠的参考来支持我的假设;我找到的所有答案都只是描述现象而不是解释原因?

【问题讨论】:

  • 除了直接调用函数之外,你可以在 C 中将函数作为对象做什么?
  • b*b 分别是 int *intbar 是指向函数的指针。但是bar 是一个指针变量,就像b — 它有存储空间。相反,foo 是地址常量,就像数组的名称是地址常量一样。它在被引用时衰减为指向函数的指针。没有必要记住太多的规则。重复引用或取消引用函数是愚蠢的(没有多个 *&)。我仍然喜欢(*pointer)(arg) 表示我正在使用指向函数的指针,但pointer(arg) 也可以正常工作。不需要在函数上使用&
  • @JonathanLeffler 嗨 John 我刚刚在代码中添加了一条注释以使我的意图更加清晰,所以如果我将 foo&foo 交换,汇编代码仍然相同,因为 @987654349 @没有存储地址,不知道是不是foo等于&foo的原因?
  • 单个编译器从您的代码中创建什么并不重要。它们不一样,因为编译器不分配内存。情况恰恰相反。编译器不需要分配内存,因为 C 标准告诉我们它们是相同的。
  • foo这样的函数的名称映射到找到它的地址; &foo 的唯一合理解释是它所在的地址。是的,它们是一样的。在函数调用符号(*pointer)(arg) 之外(指针可以是函数名,但这很愚蠢),没有理由取消对函数指针的引用。基本上,你可以用函数做两件事;获取他们的地址并打电话给他们。

标签: c function-pointers


【解决方案1】:

恐怕除了学习“所有这些规则”之外别无选择(如果“所有这些规则”是指在获取指向命名函数的指针时不需要包含与号的单一规则) .

这是一个语言设计决定,基于这样一个事实:如果您希望引用一个函数而不调用它,那么指针是唯一的方法,因此可以推断出与号(类似的论点适用于数组)。质疑此设计决策与质疑任何其他设计决策一样合理,但不太可能让您了解任何深刻的真相。

此外,上面关于任何给定编译器的输出都无关紧要的评论是绝对正确的 - 这是关于语言规范,而不是关于它的任何给定实现。

【讨论】:

  • 问题是,如果我们只将函数视为“可调用”(尽管它们应该是),那么像 &foo 这样的表达式根本不应该通过编译,因为它没有任何意义,反而会造成混淆.
  • 你似乎是这里唯一一个看到任何混乱的人!如果您想使用与号,使您的代码读取与获取变量地址时的代码相同,请使用它。设计决策很简单,& 符号应该是可选的,因为 int (*bar)()=foo; 不可能有其他含义。
猜你喜欢
  • 1970-01-01
  • 2013-06-09
  • 2022-11-10
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多