C中的函数指针内存解释 [英] Function Pointer Memory Explanation in C

查看:29
本文介绍了C中的函数指针内存解释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

int (*fptr1)(int);

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

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

Can someone briefly explain what happens in stack when we call a function pointer? What is the difference between calling a function directly in main() and calling it by function pointer in C language by the means of physical memory and process?

I tried to understand what happens in memory when we call a function with function pointer but it is not enough to me.

  1. When we call a function by pointer, does pointer have this function's location at code space?
  2. When called function is running is it same as normally called function in main()?
  3. What is the difference of calling function directly or using function pointer when code is running in a pipelined branch predictive processor?

解决方案

The best way to answer this is to look at the disassembly (slightly modified sample):

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

Results in this 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  

As you can see the assembly is virtually identical between calling the function directly and via a pointer. In both cases the CPU needs to have access to the location where the code is located and call it. The direct call has the benefit of not having to dereference the pointer (as the offset will be baked into the assembly).

  1. Yes, you can see in the assignment of the function pointer, that it stores the code address of the 'square' function.
  2. From a stack setup/tear down: Yes. From a performance perspective, there is a slight difference as noted above.
  3. There are no branches, so there is no difference here.

Edit: If we were to interject branches into the above sample, it wouldn't take very long to exhaust the interesting scenarios, so I will address them here:

In the case where we have a branch before loading (or assignment) of the function pointer, for example (in pseudo assembly):

branch zero foobar
lea square
call ptr

Then we could have a difference. Assume that the pipeline chose to load and start processing the instructions at foobar, then when it realized that we weren't actually going to take that branch, it would have to stall in order to load the function pointer, and dereference it. If we were just calling a know address, then there would not be a stall.

Case two:

lea square
branch zero foobar
call ptr

In this case there wouldn't be any difference between direct calls vs through a function pointer, as everything we need is already know if the processor starts executing down the wrong path and then resets to start executing the call.

The third scenario is when the branch follows the call, and that is obviously not very interesting from a pipeline perspective as we've already executed the subroutine.

So to fully re-answer question 3, I would say Yes, there is a difference. But then the real question is whether or not the compiler/optimizer is smart enough to move the branch after the function pointer assignment, so it falls into case 2 and not case 1.

这篇关于C中的函数指针内存解释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆