如何在C结构中使用函数指针?

时间:2022-06-04 00:15:59

I want to learn more about using function pointers in C structs as a way to emulate objects-oriented programming, but in my search, I've just found questions like this where the answer is simply to use a function pointer without describing how that would work.

我想了解更多关于在C语言结构中使用函数指针作为模拟面向对象编程的方法,但在我的搜索中,我刚刚发现这样的问题,答案只是使用函数指针而不描述如何工作。

My best guess is something like this

我最好的猜测是这样的

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

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create() {
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

But that give me compiler warnings warning: assignment from incompatible pointer type, so obviously I'm doing something wrong. Could someone please provide a small but complete example of how to use a function pointer in a C struct correctly?

但这给了我编译器警告警告:从不兼容的指针类型分配,所以很明显我做错了。有人可以提供一个小但完整的例子来说明如何在C结构中正确使用函数指针吗?

My class taught in C does not even mention these. It makes me wonder whether these are actually used by C programmers. What are the advantages and disadvantages of using function pointers in C structs?

我在C教授的课程甚至没有提到这些。这让我想知道这些是否真的被C程序员使用。在C结构中使用函数指针有哪些优缺点?

2 个解决方案

#1


10  

In your struct definition, change it to

在结构定义中,将其更改为

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*,int);
};

and now use the above function pointer in main as

现在使用main中的上述函数指针作为

thing->set_data(thing,1);

#2


12  

The answer given by Andy Stow Away fixes my compiler warning, but doesn't answer my second question. The comments to that answer given by eddieantonio and Niklas R answer my second question, but don't fix my compiler warning. So I'm pooling them together into one answer.

Andy Stow Away给出的答案修复了我的编译器警告,但没有回答我的第二个问题。 eddieantonio和Niklas R给出的答案的评论回答了我的第二个问题,但是没有修复我的编译器警告。所以我把它们汇集成一个答案。

C is not object-oriented and attempting to emulate object-oriented design in C usually results in bad style. Duplicating methods called on structs so that they can be called using a pointer to the struct as I have in my example is no exception. (And frankly, it violates DRY.) Function pointers in structs are more useful for polymorphism. For example, if I had a struct vector that represented a generic container for a linear sequence of elements, it might be useful to store a comparison_func member that was a function pointer to allow sorting and searching through the vector. Each instance of the vector could use a different comparison function. However, in the case of a function that operates on the struct itself, it is better style to have a single separate function that is not duplicated in the struct.

C不是面向对象的,并且试图在C中模拟面向对象的设计通常会导致糟糕的风格。复制方法调用结构,以便可以使用指向结构的指针调用它们,就像我在我的示例中所做的那样也不例外。 (坦率地说,它违反了DRY。)结构中的函数指针对多态性更有用。例如,如果我有一个结构向量来表示线性元素序列的通用容器,那么存储一个compare_func成员可能很有用,该成员是一个函数指针,允许对向量进行排序和搜索。向量的每个实例都可以使用不同的比较函数。但是,在对结构本身进行操作的函数的情况下,拥有一个在结构中不重复的单独函数是更好的样式。

This makes the answer to what is correct more complicated. Is what is correct how to make my above example compile? Is it how to reformat my above example so that it has good style? Or is it what is an example of a struct that uses a function pointer the way C programmer would do it? In formulating my question, I did not anticipate the answer being that my question was wrong. For completeness, I will provide an example of each answer to the question.

这使得答案更加复杂。如何使我上面的例子编译是正确的?它是如何重新格式化我的上面的例子,以便它具有良好的风格?或者它是一个使用函数指针的结构的例子,就像C程序员那样做的?在提出我的问题时,我没有预料到答案是我的问题是错的。为了完整起见,我将提供问题的每个答案的示例。

Fixing the Compiler Warning

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

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*, int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

Reformatting the Style

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

struct my_struct
{
    int data;
};

void my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    my_struct_set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

Demonstrating a Use for Function Pointer in Structs

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

struct my_struct
{
    void* data;
    int (*compare_func)(const void*, const void*);
};

int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
    return m->compare_func(m->data, comparable);
}

struct my_struct* my_struct_create(void* initial_data,
        int (*compare_func)(const void*, const void*))
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = initial_data;
    result->compare_func = compare_func;
    return result;
}

int int_compare(const void* a_pointer, const void* b_pointer)
{
    return *(int*)a_pointer - *(int*) b_pointer;
}

int string_compare(const void* a_pointer, const void* b_pointer)
{
    return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}

int main(int argc, const char* argv[])
{
    int int_data = 42;
    struct my_struct* int_comparator =
            my_struct_create(&int_data, int_compare);

    char* string_data = "Hello world";
    struct my_struct* string_comparator =
             my_struct_create(&string_data, string_compare);

    int int_comparable = 42;
    if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
    {
        printf("The two ints are equal.\n");
    }

    char* string_comparable = "Goodbye world";
    if (my_struct_compare_to_data(string_comparator,
            &string_comparable) > 0)
    {
        printf("The first string comes after the second.\n");
    }

    free(int_comparator);
    free(string_comparator);

    return 0;
}

#1


10  

In your struct definition, change it to

在结构定义中,将其更改为

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*,int);
};

and now use the above function pointer in main as

现在使用main中的上述函数指针作为

thing->set_data(thing,1);

#2


12  

The answer given by Andy Stow Away fixes my compiler warning, but doesn't answer my second question. The comments to that answer given by eddieantonio and Niklas R answer my second question, but don't fix my compiler warning. So I'm pooling them together into one answer.

Andy Stow Away给出的答案修复了我的编译器警告,但没有回答我的第二个问题。 eddieantonio和Niklas R给出的答案的评论回答了我的第二个问题,但是没有修复我的编译器警告。所以我把它们汇集成一个答案。

C is not object-oriented and attempting to emulate object-oriented design in C usually results in bad style. Duplicating methods called on structs so that they can be called using a pointer to the struct as I have in my example is no exception. (And frankly, it violates DRY.) Function pointers in structs are more useful for polymorphism. For example, if I had a struct vector that represented a generic container for a linear sequence of elements, it might be useful to store a comparison_func member that was a function pointer to allow sorting and searching through the vector. Each instance of the vector could use a different comparison function. However, in the case of a function that operates on the struct itself, it is better style to have a single separate function that is not duplicated in the struct.

C不是面向对象的,并且试图在C中模拟面向对象的设计通常会导致糟糕的风格。复制方法调用结构,以便可以使用指向结构的指针调用它们,就像我在我的示例中所做的那样也不例外。 (坦率地说,它违反了DRY。)结构中的函数指针对多态性更有用。例如,如果我有一个结构向量来表示线性元素序列的通用容器,那么存储一个compare_func成员可能很有用,该成员是一个函数指针,允许对向量进行排序和搜索。向量的每个实例都可以使用不同的比较函数。但是,在对结构本身进行操作的函数的情况下,拥有一个在结构中不重复的单独函数是更好的样式。

This makes the answer to what is correct more complicated. Is what is correct how to make my above example compile? Is it how to reformat my above example so that it has good style? Or is it what is an example of a struct that uses a function pointer the way C programmer would do it? In formulating my question, I did not anticipate the answer being that my question was wrong. For completeness, I will provide an example of each answer to the question.

这使得答案更加复杂。如何使我上面的例子编译是正确的?它是如何重新格式化我的上面的例子,以便它具有良好的风格?或者它是一个使用函数指针的结构的例子,就像C程序员那样做的?在提出我的问题时,我没有预料到答案是我的问题是错的。为了完整起见,我将提供问题的每个答案的示例。

Fixing the Compiler Warning

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

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*, int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

Reformatting the Style

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

struct my_struct
{
    int data;
};

void my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    my_struct_set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

Demonstrating a Use for Function Pointer in Structs

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

struct my_struct
{
    void* data;
    int (*compare_func)(const void*, const void*);
};

int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
    return m->compare_func(m->data, comparable);
}

struct my_struct* my_struct_create(void* initial_data,
        int (*compare_func)(const void*, const void*))
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = initial_data;
    result->compare_func = compare_func;
    return result;
}

int int_compare(const void* a_pointer, const void* b_pointer)
{
    return *(int*)a_pointer - *(int*) b_pointer;
}

int string_compare(const void* a_pointer, const void* b_pointer)
{
    return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}

int main(int argc, const char* argv[])
{
    int int_data = 42;
    struct my_struct* int_comparator =
            my_struct_create(&int_data, int_compare);

    char* string_data = "Hello world";
    struct my_struct* string_comparator =
             my_struct_create(&string_data, string_compare);

    int int_comparable = 42;
    if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
    {
        printf("The two ints are equal.\n");
    }

    char* string_comparable = "Goodbye world";
    if (my_struct_compare_to_data(string_comparator,
            &string_comparable) > 0)
    {
        printf("The first string comes after the second.\n");
    }

    free(int_comparator);
    free(string_comparator);

    return 0;
}