C语言函数指针内存解释

2024-03-01

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

int (*fptr1)(int);

int square(int num){
  return num*num;
}

void main(){
  fptr1 = &square;
  printf("%d\n",fptr1(5));
}

有人可以简单解释一下当我们调用函数指针时堆栈中发生了什么吗?在main()中直接调用函数和C语言中通过物理内存和进程的方式通过函数指针调用有什么区别?

我试图了解当我们使用函数指针调用函数时内存中会发生什么,但这对我来说还不够。

  1. 当我们通过指针调用函数时,指针是否有该函数在代码空间的位置?
  2. 当被调用函数运行时,它与 main() 中正常调用的函数相同吗?
  3. 当代码在流水线分支预测处理器中运行时,直接调用函数或使用函数指针有什么区别?

回答这个问题的最佳方法是查看反汇编(稍微修改的示例):

fptr1 = &square;
int result1 = fptr1(5);
int result2 = square(5);

此 x64 asm 的结果:

    fptr1 = &square;
000000013FA31A61  lea         rax,[square (013FA31037h)]  
000000013FA31A68  mov         qword ptr [fptr1 (013FA40290h)],rax  
    int result1 = fptr1(5);
000000013FA31A6F  mov         ecx,5  
000000013FA31A74  call        qword ptr [fptr1 (013FA40290h)]  
000000013FA31A7A  mov         dword ptr [result1],eax  
    int result2 = square(5);
000000013FA31A7E  mov         ecx,5  
000000013FA31A83  call        square (013FA31037h)  
000000013FA31A88  mov         dword ptr [result2],eax  

正如您所看到的,直接调用函数和通过指针调用函数之间的程序集实际上是相同的。在这两种情况下,CPU 都需要访问代码所在的位置并调用它。直接调用的好处是不必取消引用指针(因为偏移量将被烘焙到程序集中)。

  1. 是的,你可以在函数指针的赋值中看到, 它存储“square”函数的代码地址。
  2. 来自堆栈 安装/拆卸:是的。从性能的角度来看,有一个 如上所述,略有差异。
  3. 没有分支,所以这里没有区别。

Edit:如果我们将分支插入到上面的示例中,不需要很长时间就能穷尽有趣的场景,所以我将在这里解决它们:

例如,在加载(或赋值)函数指针之前我们有一个分支的情况(在伪汇编中):

branch zero foobar
lea square
call ptr

Then we could有区别。假设管道选择加载并开始处理指令foobar,然后当它意识到我们实际上并不打算采用该分支时,它必须停止以加载函数指针并取消引用它。如果我们只是呼叫一个已知地址,那么就不会出现停顿。

情况二:

lea square
branch zero foobar
call ptr

在这种情况下,直接调用与通过函数指针调用之间不会有任何区别,因为我们需要的一切都已经知道处理器是否开始沿着错误的路径执行,然后重置以开始执行调用。

第三种情况是分支跟随调用,从管道的角度来看,这显然不是很有趣,因为我们已经执行了子例程。

所以要完全重新回答问题3,我会说是的,有区别。但真正的问题是编译器/优化器是否足够聪明来移动分支after函数指针赋值,因此属于情况 2 而不是情况 1。

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

C语言函数指针内存解释 的相关文章

  • C# 打印问题(RichTextBox)

    我想打印我的 RichTextBox eintragRichTextBox 的内容 我现在有这个代码 private void druckenPictureBox Click object sender EventArgs e PrintD
  • CMake 找不到请求的 Boost 库

    既然我已经浏览了其他人的解决方案几个小时 但找不到适合我的问题的正确答案 我想将我的具体问题带给您 我正在尝试使用 CMake 构建 vsomeip 为此 我之前构建了 boost 1 55 但是 我在 CMake 中收到以下错误 The
  • 在 OnModelCreating 期间设置列名称

    Issue 我目前正在尝试通过设置的属性为我的表及其列添加前缀 我正在使用实体框架核心 我已经正确地为表名添加了前缀 但我似乎无法弄清楚列的前缀 我有一种感觉 我需要使用反射 我已经留下了我的 可能很糟糕的 反思尝试 有人有办法在实体中设置
  • 删除是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 C 编程 free 如何知道要释放多少 https stackoverflow com questions 1518711 c programming how does free know how m
  • 在现代 C++ 中,临时生命周期延长何时有用?

    在 C 中 您可以将函数的返回值 返回值 而不是引用 绑定到 const 引用 并且代码仍然有效 因为该临时对象的生命周期将延长到作用域末尾 例如 std string get string return abc void f const
  • 将表(行)与 OpenXML SDK 2.5 保持在一起

    我想在 Word 文档中生成多个表 每行 2 行 但我想将这两行保留在一起 如果可能的话 new KeepNext 第一行不起作用 new KeepNext 第一行的最后一段不起作用 new CantSplit 放在桌子上不起作用 在所有情
  • UI 函数在快速事件完成之前触发

    我有一个停靠在 Silverlight 应用程序中的 Web 浏览器框架 有时会在其上弹出全窗口 XAML Silverlight UI 元素 我已经或多或少修复了一个老问题 即 Web 框架的内容似乎与 Silverlight 内容不能很
  • 在 asp.net MVC 中使用活动目录进行身份验证

    我想使用活动目录对我的 asp net mvc 项目中的用户进行身份验证 在网上冲浪了几个小时后 我没有找到任何对我有用的东西 我已经看到了所有结果 但什么也没有 我尝试按照许多帖子的建议编辑我的 web config 如果有人可以帮助我提
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 使用具有抗锯齿功能的 C# 更改抗锯齿图像的背景颜色

    我有一个图像需要更改背景颜色 例如 将下面示例图像的背景更改为蓝色 然而 图像是抗锯齿的 所以我不能简单地用不同的颜色替换背景颜色 我尝试过的一种方法是创建第二个图像 仅作为背景 并更改其颜色并将两个图像合并为一个图像 但是这不起作用 因为
  • 如何使用 NPOI 按地址(A1、A2)获取 Excel 单元格值

    我有一个 Excel 单元格地址 例如 A1 A2 如何使用 C 中的 NPOI 框架以编程方式访问此单元格 我找到的一些 Java POI 示例代码 CellReference cr new CellReference A1 row my
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • ASP.NET MVC 路由:如何从 URL 中省略“索引”

    我有一个名为 StuffController 的控制器 具有无参数索引操作 我希望从表单中的 URL 调用此操作mysite com stuff 我的控制器定义为 public class StuffController BaseContr
  • 选择查询不适用于使用Parameters.AddWithValue 的参数

    C 中的以下查询不起作用 但我看不出问题所在 string Getquery select from user tbl where emp id emp id and birthdate birthdate cmdR Parameters
  • 在 C#.NET 中安全删除文件

    在我正在做的一个项目中 我想为用户提供 安全 删除文件的选项 例如 用随机位或 0 覆盖它 在 C NET 中是否有一种简单的方法可以做到这一点 效果如何 你可以调用系统内部删除 http technet microsoft com en
  • C++ 中 void(*)() 和 void(&)() 之间的区别[重复]

    这个问题在这里已经有答案了 在此示例代码中 func1是类型void int double and funky是类型void int double include
  • INotifyPropertyChanged 和 propertyName

    我一直不确定它的含义propertyName实施时INotifyPropertyChanged 所以一般来说你实现INotifyPropertyChanged as public class Data INotifyPropertyChan
  • 结构化绑定的用例有哪些?

    C 17 标准引入了新的结构化绑定 http en cppreference com w cpp language structured binding功能 最初是proposed http www open std org jtc1 sc
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include
  • 使用未分配的局部变量

    我遇到了一个错误 尽管声明了变量 failturetext 和 userName 错误仍然出现 谁能帮帮我吗 Use of Unassigned local variable FailureText Use of Unassigned lo

随机推荐