- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我读到了 C 中的函数指针。每个人都说这会使我的程序运行缓慢。是真的吗?
我编写了一个程序来检查它。我在这两种情况下都得到了相同的结果。 (测量时间。)
那么,使用函数指针不好吗?提前致谢。
对某些人的回应。我说的是我在循环中比较过的时间“运行缓慢”。像这样:
int end = 1000;
int i = 0;
while (i < end) {
fp = func;
fp ();
}
当你执行这个的时候,如果我执行这个我得到了同样的时间。
while (i < end) {
func ();
}
所以我认为函数指针没有时间差而且它不会像许多人所说的那样使程序运行缓慢。
最佳答案
你看,在从性能的角度来看真正重要的情况下,比如在一个循环中多次重复调用该函数,性能可能根本没有什么不同。
这对于习惯于将 C 代码视为由抽象 C 机器执行的代码的人来说可能听起来很奇怪,其“机器语言”与 C 语言本身非常相似。在这种情况下,“默认情况下”对函数的间接调用确实比直接调用慢,因为它正式涉及额外的内存访问以确定调用目标。
然而,在现实生活中,代码是由真实机器执行并由优化编译器编译的,该编译器非常了解底层机器架构,这有助于它为该特定机器生成最佳代码。在许多平台上,从循环中执行函数调用的最有效方法实际上会导致直接调用和间接调用的代码相同,从而导致两者具有相同的性能。
例如,考虑 x86 平台。如果我们“从字面上”将直接和间接调用翻译成机器代码,我们可能会得到这样的结果
// Direct call
do-it-many-times
call 0x12345678
// Indirect call
do-it-many-times
call dword ptr [0x67890ABC]
前者在机器指令中使用立即操作数,确实通常比后者更快,后者必须从某个独立的内存位置读取数据。
此时让我们记住,x86 架构实际上还有一种方法可以为 call
指令提供操作数。它在寄存器 中提供目标地址。这种格式的一个非常重要的事情是它通常比上面两种格式都快。这对我们意味着什么?这意味着一个好的优化编译器必须而且将会利用这一事实。为了实现上述循环,编译器将尝试在两种情况下都使用通过寄存器的调用。如果成功,最终代码可能如下所示
// Direct call
mov eax, 0x12345678
do-it-many-times
call eax
// Indirect call
mov eax, dword ptr [0x67890ABC]
do-it-many-times
call eax
请注意,现在重要的部分 - 循环体中的实际调用 - 在两种情况下都完全相同。不用说,性能将几乎相同。
有人甚至可能会说,无论听起来多么奇怪,在这个平台上,直接调用(在 call
中使用立即操作数的调用)比间接调用慢只要间接调用的操作数在寄存器中提供(而不是存储在内存中),就可以调用。
当然,在一般情况下,整个事情并不那么容易。编译器必须处理有限的寄存器可用性、别名问题等。但是像你的例子中的例子(甚至更复杂的例子)这样的简单情况,上面的优化将由一个好的编译器执行,并将完全消除循环直接调用和循环间接调用之间的性能差异。这种优化在 C++ 中特别有效,当调用虚函数时,因为在典型的实现中,所涉及的指针完全由编译器控制,使其完全了解别名图片和其他相关内容。
当然,你的编译器是否足够智能来优化这样的事情总是一个问题......
关于c - 函数指针会使程序变慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2438539/
我已经在谷歌上搜索这个问题一段时间了,但我还没有找到有效的解决方案。 问题是 SSH 登录到我的服务器突然变得很慢。我可以看到身份验证需要大约 10 秒才能继续,这是我的 ssh 详细日志: Open
我正在使用 AVPlayer 在我的项目中播放在线视频。视频播放良好。现在我想减少/增加视频的 fps。以下是我正在使用的代码: self.asset = [AVAsset assetWithURL:
在 Raspberry Pi 上运行两个使用 python gpio 引脚的程序时,一个变慢。一种是磁传感器,另一种是温湿度传感器。后者是放慢速度的。它不是每 2 秒打印一次温度,而是每 5 到 10
我从 Redis 向我的应用程序提供一个 json,然后我对其进行解码和循环。 这是我从 Redis 提供的 json 的样子: [ { "titel": "test 1",
Ejabberd 版本:19.9.0 在发送 OMEMO 消息时(使用 websockets),例如
我们有相当大的代码库(150 多个项目、400000 多行 Java 代码、一些 Groovy 和 Gradle 代码、一些 Perl 代码、一些 XML、大量 JSP 等)。我设法在 Spring
我在一个网站上工作,您可以在其中创建 svg 艺术品,这意味着您可以动态添加元素、缩放、颜色并移动它们。 问题是,当你开始在他们身上施加阴影时,一切都会开始变慢。对于这个的现场演示,this是我正在开
有没有办法分析 Vim 插件? 当我打开一个大的 .py 时,我的 MacVim 变得越来越慢。我知道我可以取消选择所有插件并逐一重新选择以检查哪个插件是罪魁祸首,但是有没有更快的方法? 我的 dot
我正在构建一个JavaFX应用程序。我知道它使用反射,并且反射可能不如我在代码中构建 UI 时那么快。 所以, 如何设计我的 Controller 以使由反射引起的开销尽可能小? 带/不带 @FXML
我对 UITableViewCell 进行了子类化显示从 1 到 70 的数字。 在每个单元格中,我都在检查中奖号码并检查他们的背景。问题是,经过几次滚动后,tableview 变得非常缓慢,甚至无法
如果我想group_by 和filter 那些在数据集中有任何NA 或factor 值的,我想在 dplyr 中使用 any 函数,但发现它对 NAs 或 factor 运行缓慢(但不是为了寻找任何数
我有一个问题。在我的解决方案中,我需要将数千个数据插入数据库。我正在使用批处理准备语句在一个请求中插入多行。在我调用插入几次之后, hibernate 变得更慢了。 我猜它会在我提交后检查数据库是否有
我从 json url 获取数据,但是当我想加载图像时,速度非常慢! class NewsTableViewController: UITableViewController { var id
我有一个相当简单的托管 Realm 对象 RealmAlertItem由一些字符串和 float 组成。我有一个函数 showAlertNotification()随后被调用(从网络外部触发)并且它依
请参阅下面的表格结构。 CREATE TABLE `oarc` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT, `zID` int(11) NOT N
IntelliJ 慢得像爬行。键之间没有 1-2 个延迟几乎无法打字。我已经更新了堆大小。我在我的 Macbook Pro 上运行大约 2GB RAM。自从它一直在放缓。我已经增加了堆大小,但无济于事
我的 Web 应用程序遇到了性能问题。发现瓶颈是db。应用程序在具有 4 个 CPU 和 2GB RAM 的 LAMP 服务器 (VPS) 上运行。 将新记录插入数据库(包含大约 100.000 条记
我有关于自定义 DispatchQueue 的问题。 我创建了一个队列,并将其用作captureOutput:方法的队列。这是一个代码片段: //At the file header private
我是一名移动 QA。现在我们有一个关于网络响应和 UI 渲染之间的竞争条件的问题。我们猜测如果 UI 渲染比网络响应慢,那么它就会崩溃。 我们已经尝试通过使用 Charles 的本地 map 功能来加
我在 firefox 中遇到了一些奇怪的行为,我正在构建一个单页作品集,作为一名平面设计师,编码一直很困难。我想平滑地控制导航,然后向所有元素添加缩放(最初设计为 1920x1080 全屏)。讲师扔了
我是一名优秀的程序员,十分优秀!