函数指针,才是一切一切的根基

1.  前言

最近工作中,在干一件事情,就是打通从安卓的java代码,到JNI,最后到server端的C代码。

当然这个过程,早已有大神们做好了,我只是根据当前的业务需要,定制化的实现这个过程。

那这和函数指针,有啥关系呢?请先看程序和内存的关联关系。


2.  C语言中的内存布局

C语言的内存布局[1], 如下图所示


任何一个C语言可执行程序,以有组织的方式加载到计算机内存当中,这段内存被称为进程地址空间或者C程序的内存布局。


通常,将这个内存布局,分为如下几个部分:

(1)Text segment  ——文本段

文本段包含C程序的可执行指令,也称为代码段。文本段是不同的进程之间可共享的

(2)Data segment —— 数据段

这里分为2个子段:初始化数据段和未初始化数据段。通俗的说,不为0的全局变量和静态变量,会存储在初始化数据段。其余的变量会存储在未初始化数据段。

(3)Heap segment —— 堆

在堆区,我们可以动态的开辟和释放内存。开辟内存可以使用malloc(), calloc(), realloc() and new for C++。释放内存可以使用free() or delete。

(4)Stack segment —— 栈

所有函数当中声明的变量,会存储在栈区,存储内容也包括地址,形参等信息。当我们调用某个函数,会创建一个stack frame,当函数返回之后,stack frame将会被销毁。stack pointer将会记录所有的出栈,入栈信息。

每一个函数都拥有自己的stack frame,当调用函数时,stack frame的结构图如下:


(5)Unmapped or reserved —— 预留段

未映射或预留段包含命令行参数和其他程序相关数据,如可执行映像的较低地址,较高地址等。


3.  函数指针

(1)函数指针:指向函数地址的指针。

A function pointer is a pointer that refers to the address of a function.

一个典型的函数指针,如下:

int (*func)(int a, float b);

(2)函数指针的例子[2]——异步调用

demo1 : 

/ * This code catches the alarm signal generated from the kernel
    Asynchronously */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
 
struct sigaction act;
 
/* signal handler definition goes here */
void sig_handler(int signo, siginfo_t *si, void *ucontext)
{
   printf("Got alarm signal %d\n",signo);
   /* do the required stuff here */
}
 
int main(void)
{
    act.sa_sigaction = sig_handler;
    act.sa_flags = SA_SIGINFO;
 
    /* register signal handler */
    sigaction(SIGALRM, &act, NULL);  
    /* set the alarm for 10 sec */       
    alarm(10);   
    /* wait for any signal from kernel */                                        
    pause();  
    /* after signal handler execution */                                             
    printf("back to main\n");                     
    return 0;
}




demo2:

/* insertion_sort.h */
 
typedef int (*callback)(int, int);
void insertion_sort(int *array, int n, callback comparison);

/* insertion_main.c */
 
#include<stdio.h>
#include<stdlib.h>
#include"insertion_sort.h"
 
int ascending(int a, int b)
{
    return a > b;
}
 
int descending(int a, int b)
{
    return a < b;
}
 
int even_first(int a, int b)
{
    /* code goes here */
}
 
int odd_first(int a, int b)
{
    /* code goes here */
}
 
int main(void)
{
    int i;
    int choice;
    int array[10] = {22,66,55,11,99,33,44,77,88,0};
    printf("ascending 1: descending 2: even_first 3: odd_first 4: quit 5\n");
    printf("enter your choice = ");
    scanf("%d",&choice);
    switch(choice)
    {
        case 1:
            insertion_sort(array,10, ascending);
            break;
        case 2:
            insertion_sort(array,10, descending);
         case 3:
            insertion_sort(array,10, even_first);
            break;
        case 4:
            insertion_sort(array,10, odd_first);
            break;
        case 5:
            exit(0);
        default:
            printf("no such option\n");
    }
 
    printf("after insertion_sort\n");
    for(i=0;i<10;i++)
        printf("%d\t", array[i]);
    printf("\n");
     return 0;
}

/* insertion_sort.c */
 
#include"insertion_sort.h"
 
void insertion_sort(int *array, int n, callback comparison)
{
    int i, j, key;
    for(j=1; j<=n-1;j++)
    {
        key=array[j];
        i=j-1;
        while(i >=0 && comparison(array[i], key))
        {
            array[i+1]=array[i];
            i=i-1;
        }
        array[i+1]=key;
    }
}


从以上2个demo,已经可以很明显的看出函数指针的用途和用法。

不过,这和开始说的,函数指针是一切的根基,好像毫无关联啊,怎么看都是一种编程技巧嘛。

别急,往下看。


4.  再探内存地址和程序的关系

有人曾经说过,c语言的精华是指针,我认为这句话没有说完,c语言的精华是函数指针才对。

为什么这么说?

既然,程序只不过是内存的一部分。而函数是程序的一部分。

那换句话说,其实程序就是计算机按照一定顺序访问内存地址的过程。

那么,只要能够控制(获取)内存地址,就等于掌握了计算机。

说到这里,函数指针的意义已经很明确了。


那么,安卓的java代码,与JNI的C代码,再到server的C代码,到底怎么交互呢?

很简单,互相传递函数指针,一切搞定!




参考文献:

[1]http://www.firmcodes.com/memory-layout-c-program-2/

[2]http://opensourceforu.com/2012/02/function-pointers-and-callbacks-in-c-an-odyssey/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值