简体   繁体   English

试图理解C中的函数指针

[英]Trying to understand function pointers in C

I am trying to understand function pointers and am stuggling. 我正在尝试理解函数指针并且正在捣乱。 I have seen the sorting example in K&R and a few other similar examples. 我已经看到了K&R中的排序示例以及其他一些类似的示例。 My main problem is with what the computer is actually doing. 我的主要问题是计算机实际上在做什么。 I created a very simple program to try to see the basics. 我创建了一个非常简单的程序来尝试查看基础知识。 Please see the following: 请参阅以下内容:

#include <stdio.h>

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23,(int(*)(void*,void*))(i==1?func0:func1));//34 and 23 are arbitrary inputs



}

void myfunc(int x, int y, int(*somefunc)(void *, void *)){

    int *xx =&x;
    int *yy=&y;

    printf("%i",somefunc(xx,yy));


}

int func0(int *x, int *y){

    return (*x)*(*y);

}

int func1(int *x, int *y){

    return *x+*y;
} 

The program either multiplies or adds two numbers depending on some variable (i in the main function - should probably be an argument in the main). 程序要么根据某个变量相乘或相加两个数字(i在主函数中 - 应该是主要的参数)。 fun0 multiplies two ints and func1 adds them. fun0乘以两个整数,func1将它们相加。

I know that this example is simple but how is passing a function pointer preferrable to putting a conditional inside the function myfunc? 我知道这个例子很简单,但是如何传递一个函数指针,可以在函数myfunc中放入一个条件? ie in myfunc have the following: 即在myfunc中有以下内容:

if(i == 1)printf("%i",func0(xx,yy));

else printf("%i",func1(xx,yy));

If I did this the result would be the same but without the use of function pointers. 如果我这样做,结果将是相同的但不使用函数指针。

Your understanding of how function pointers work is just fine. 您对函数指针如何工作的理解很好。 What you're not seeing is how a software system will benefit from using function pointers. 您没有看到的是软件系统如何从使用函数指针中受益。 They become important when working with components that are not aware of the others. 在使用不了解其他组件的组件时,它们变得很重要。

qsort() is a good example. qsort()就是一个很好的例子。 qsort will let you sort any array and is not actually aware of what makes up the array. qsort将允许您对任何数组进行排序,并且实际上并不知道组成数组的内容。 So if you have an array of structs, or more likely pointers to structs, you would have to provide a function that could compare the structs. 因此,如果你有一个结构数组,或更可能指向结构的指针,你将不得不提供一个可以比较结构的函数。

struct foo {
  char * name;
  int magnitude;
  int something;
};

int cmp_foo(const void *_p1, const void *_p2)
{
  p1 = (struct foo*)_p1;
  p2 = (struct foo*)_p2;

  return p1->magnitude - p2->magnitude;
}

struct foo ** foos;
// init 10 foo structures...

qsort(foos, 10, sizeof(foo *), cmp_foo);

Then the foos array will be sorted based on the magnitude field. 然后将根据幅度字段对foos数组进行排序。

As you can see, this allows you to use qsort for any type -- you only have to provide the comparison function. 如您所见,这允许您对任何类型使用qsort - 您只需提供比较功能。

Another common usage of function pointers are callbacks, for example in GUI programming. 函数指针的另一个常见用法是回调,例如在GUI编程中。 If you want a function to be called when a button is clicked, you would provide a function pointer to the GUI library when setting up the button. 如果希望在单击按钮时调用函数,则在设置按钮时将提供指向GUI库的函数指针。

how is passing a function pointer preferrable to putting a conditional inside the function myfunc 如何将函数指针传递给函数myfunc中的条件

Sometimes it is impossible to put a condition there: for example, if you are writing a sorting algorithm, and you do not know what you are sorting ahead of time, you simply cannot put a conditional; 有时候不可能在那里设置一个条件:例如,如果你正在编写一个排序算法,并且你不知道你提前排序的是什么,你根本就不能提出条件; function pointer lets you "plug in" a piece of computation into the main algorithm without jumping through hoops. 函数指针允许您将一段计算“插入”主算法,而不会跳过箍。

As far as how the mechanism works, the idea is simple: all your compiled code is located in the program memory, and the CPU executes it starting at a certain address. 至于机制如何工作,这个想法很简单:所有编译的代码都位于程序存储器中,CPU从某个地址开始执行它。 There are instructions to make CPU jump between addresses, remember the current address and jump, recall the address of a prior jump and go back to it, and so on. 有指令使CPU在地址之间跳转,记住当前地址和跳转,调用先前跳转的地址并返回到它,等等。 When you call a function, one of the things the CPU needs to know is its address in the program memory. 当你调用一个函数时,CPU需要知道的一件事就是它在程序存储器中的地址。 The name of the function represents that address. 函数的名称代表该地址。 You can supply that address directly, or you can assign it to a pointer for indirect access. 您可以直接提供该地址,也可以将其分配给指针以进行间接访问。 This is similar to accessing values through a pointer, except in this case you access the code indirectly, instead of accessing the data. 这类似于通过指针访问值,除非在这种情况下您间接访问代码,而不是访问数据。

First of all, you can never typecast a function pointer into a function pointer of a different type. 首先,您永远不能将函数指针强制转换为不同类型的函数指针。 That is undefined behavior in C (C11 6.5.2.2). 这是C中的未定义行为(C11 6.5.2.2)。

A very important advise when dealing with function pointers is to always use typedefs. 处理函数指针时,一个非常重要的建议是始终使用typedef。

So, your code could/should be rewritten as: 因此,您的代码可以/应该重写为:

typedef int (*func_t)(int*, int*);

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23, (i==1?func0:func1)); //34 and 23 are arbitrary inputs
}

void myfunc(int x, int y, func_t func){

To answer the question, you want to use function pointers as parameters when you don't know the nature of the function. 要回答这个问题,当您不知道函数的性质时,您希望使用函数指针作为参数。 This is common when writing generic algorithms. 这在编写通用算法时很常见。

Take the standard C function bsearch() as an example: 以标准C函数bsearch()为例:

void *bsearch (const void *key, 
               const void *base,
               size_t nmemb, 
               size_t size,
               int (*compar)(const void *, const void *));
              );

This is a generic binary search algorithm, searching through any form of one-dimensional arrray, containing unknown types of data, such as user-defined types. 这是一种通用的二进制搜索算法,搜索任何形式的一维arrray,包含未知类型的数据,例如用户定义的类型。 Here, the "compar" function is comparing two objects of unknown nature for equality, returning a number to indicate this. 这里,“比较”函数比较两个未知性质的对象是否相等,返回一个数字来表示这一点。

"The function shall return an integer less than, equal to, or greater than zero if the key object is considered, respectively, to be less than, to match, or to be greater than the array element." “如果分别考虑密钥对象,该函数应返回小于,等于或大于零的整数,以小于,匹​​配或大于数组元素。”

The function is written by the caller, who knows the nature of the data. 该函数由调用者编写,调用者知道数据的性质。 In computer science, this is called a "function object" or sometimes "functor". 在计算机科学中,这被称为“功能对象”或有时称为“仿函数”。 It is commonly encountered in object-oriented design. 它在面向对象的设计中经常遇到。

An example (pseudo code): 一个例子(伪代码):

typedef struct  // some user-defined type
{
  int* ptr;
  int  x;
  int  y;
} Something_t;

int compare_Something_t (const void* p1, const void* p2)
{
  const Something_t* s1 = (const Something_t*)p1;
  const Something_t* s2 = (const Something_t*)p2;

  return s1->y - s2->y;  // some user-defined comparison relevant to the object
}

...

Something_t  search_key = { ... };
Something_t  array[] = { ... };
Something_t* result; 

result = bsearch(&search_key,
                 array,
                 sizeof(array) / sizeof(Something_t), // number of objects
                 sizeof(Something_t), // size of one object
                 compare_Something_t // function object
                );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM