嵌入式技术
文章开始前先抛出一个经典的面试题:
凡是学过C语言函数的应该都知道,函数名其实就是个地址,是函数的入口地址。如果用 %p 来输出函数名,确实可以得到一个合法的地址。
#includeint function(int a, int b) { printf("this is test ... "); } int main() { printf("%p ", function); return 0; }
运行结果:
root@Turbo:test# ./test 0x55a061ec3169
指针是用来保存地址的,那能不能把函数名直接赋值给指针呢?这个操作是可以的,这种指针我们把它称作函数指针。字符指针是char *,整型指针是int *,那函数指针应该怎么写?
假设有这么一个函数,返回值是整型,参数有两个。
int function(int a, int b) { printf("this is test ... "); }
如果要定义指针保存该函数的地址,应该写成这样。
int (*pFunction)(int, int);
其实分析起来也不难,用我之前给大家讲的右左法则。
先找到变量名 pFunction,向右看,是个右括号,再向左看,是个星号,于是得出结论,pFunction是个指针。然后再向右看,又是括号,C语言中括号除了表示优先级,剩下的就是函数会使用,所以指针指向函数。继续分析,函数有两个参数,函数的返回值是int。
既然是定义变量,就可以直接在后面初始化变量。
int (*pFunction)(int, int) = function;
于是指针 pFunction 就指向了函数function。调用函数的时候,不仅可以通过函数名调用,也能通过函数指针调用。
function(1, 2); pFunction(1, 2);
注意:有个小问题,通过函数指针调用函数的时候,指针前面可以加星号,也可以不加星号,编译器都能通过,运行结果也一样。至于说哪种更合适,一直备受争论。
(*pFunction)(1, 2);
如果代码里面用到函数指针的地方太多,每次定义就显得比较麻烦。
int (*pFunction1)(int, int) = function; int (*pFunction2)(int, int) = function; int (*pFunction3)(int, int) = function;
如果是同一个类型的函数指针,我们完全可以使用 typedef 关键字来简化它.
typedef int (*T)(int, int);
写成这样,看起来非常的不顺眼,但是语法是没有问题的,意思就是用T来表示这种函数指针类型。接下来再定义变量的时候,可以直接写成:
T pFunction1 = function; T pFunction2 = function; T pFunction3 = function;
那么pFunction1的含义跟pFunction是一样的,都是函数指针。
最后,再回到文章开头的面试题。
如果是汇编语言,想要实现跳转直接就是一条指令。但是C语言中能跳转的语句不多,我能想到的就是调用函数以及goto语句。goto语句是通过标签来跳转,标签可操作空间不大,可以直接放弃。
剩下的就是函数。只要把给定的地址强转成函数指针,通过调用函数的形式,就能跳转到指定地址运行。
void (*p)(void) = 0x1000; p();
不过这样写编译器会提示警告,编译器不允许直接把整数赋值给指针。需要加上强制类型转换。
void (*p)(void) = (void (*)(void))0x1000; p();
可以简写成:
(void(*)(void))0x1000();
或者:
(*((void(*)(void))0x1000))();
全部0条评论
快来发表一下你的评论吧 !