C 中函数指针语法的用途是什么?

2024-03-03

编辑:有人指出这个问题有点令人困惑。简短的版本是:“为什么有一个单独的指针变量(例如,fnPtr)它指向一个函数(例如,fn) 当函数名fn本身,没有参数,已经是一个指针? /编辑

我正在尝试了解一些内容,并且可以使用社区有关函数指针的反馈。 (虽然这可能看起来像该主题的其他问题的重复,但实际上不是,至少我找不到。)

我理解指向函数的指针被用作另一个函数的参数作为回调的概念......即告诉fn1 to use fn2在执行过程中以某种方式fn1。我不明白的是所有这些都使用了复杂的语法。如果fn是一个定义的函数,然后调用fn(...)将使用提供的参数执行该函数。然而,fn单独使用的是函数的地址,即指向函数的指针。此外,fn, &fn, and *fn都是一样的东西。为什么有专用的函数指针,以及为什么创建新变量(即,fnPtr) 指向一个函数...函数名已经是它自己的指针了!

这段代码每次编译和运行都是一样的。

#include <stdlib.h>
#include <stdio.h>

int fn(int var) { //fn is a function which takes an int and returns an int
    return var;
}

int (*fnPtrAmp)(int) = &fn;
int (*fnPtr)(int) = fn;

int needsCallback(int variable, int callback(int)) {
    return callback(variable);
}

int needsCallbackPointer(int variable, int (*callbackPtr)(int)) {
    return callbackPtr(variable);
}

int needsCallbackPointerWithDereference(int variable, int (*callbackPtr)(int)) {
    return (*callbackPtr)(variable);
}

int main() {
    printf("%d\n", fn(4));
    printf("%d\n", fnPtr(4));
    printf("%d\n", (*fnPtr)(4));
    printf("%d\n", needsCallback(4,fn));
    printf("%d\n", needsCallbackPointer(4,fnPtr));
    printf("%d\n", needsCallbackPointer(4,fn));
    printf("%d\n", needsCallbackPointer(4,&fn));
    printf("%d\n", needsCallbackPointerWithDereference(4,fnPtr));
    printf("%d\n", needsCallbackPointerWithDereference(4,fn));
    printf("%d\n", needsCallbackPointerWithDereference(4,&fn));
    return 0;
}

最简单的语法是needsCallback但这并没有在任何地方完成,它总是needsCallbackPointer and fnPtrAmp。为什么?和needsCallback您甚至不必定义额外的变量作为函数指针。正如我之前所说,函数名称是它自己的指针!

可以使用一些反馈...谢谢。


  1. 函数指针变量当随后的控制流修改函数指针(例如选择不同的回调)时非常有用。

    函数指针变量在处理运行时绑定时也很有用,您在编译时不知道函数,而是在运行时分配函数指针,例如通过使用dlsym。这通常用于可扩展 API(例如,OpenGL 是该方案的流行用户)和插件的上下文中。

  2. “最简单的语法是needsCallback,但没有在任何地方完成,它总是needsCallbackPointer和fnPtrAmp。为什么?”:使函数参数中的声明与变量或typedef声明的外观一致。

  3. 你问的另一个问题是why *fnPtr有效,以及为什么括号.

    好吧,括号是必需的,因为函数调用运算符()具有比解引用运算符更高的优先级*,因此首先调用该函数,然后取消引用返回值。(*fnPtr)()围绕这个工作。

  4. someFunction and &someFunction是等价的,因为函数不是 C 中的一等公民(函数不是可以操作的普通对象,就像int,例如),但函数指针是。因此,函数名称总是本质上转换为指向该名称引用的函数的函数指针。请注意,您可以申请&多次指向函数指针,产生指向函数指针的指针、指向函数指针的指针等。因此,它的行为并不像*确实如此,您可以在函数指针上随意使用它。

  5. *fnPtr有效,因为*在函数指针上使用的运算符本质上会产生完全相同的指针。与 4) 的基本原理相同 - 语言中没有函数对象。因此,您无法从函数指针获取函数名称,这是不可能的。

我不知道为什么这些运算符分别为函数名和指针定义。也许是历史原因?为了与其他指针类型保持一致?

我怀疑后来引入了无运算符语法以节省键入,因为您无法在右值或左值上下文中有意义地使用函数名称。因为人们对函数指针也无能为力(除了传递它之外)。您当然可以更改它,例如fnPtr++;但这对你有什么好处?),添加隐式转换非常有意义fnPtr()可能,再次节省打字。

(最后两段纯粹是我的猜测。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中函数指针语法的用途是什么? 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐