简体   繁体   English

C数组结构函数指针

[英]C array struct function pointer

How do you create a function pointer with struct table such as 如何使用struct表创建函数指针,例如

static struct {
  int pid;
  int queue[MAXPROCS];
} semtab[MAXSEMS];

I think I understand how to make OO equivalent in C using function pointer with this post , but how can I do with when my struct is an array. 我想我了解如何在这篇文章中使用函数指针在C中实现OO等效,但是当我的struct是数组时如何处理。 I'm still a little iffy with the syntax. 我仍然对语法有些怀疑。

Would it be something like 会不会像

static struct {
  int pid;
  int queue[MAXPROCS];

  void (*fncPtr_enqueue)(int) = enqueue;
                 // or is it void(*enqueue)(semtable[]*) ?
  int (*fcnPtr_dequeue)() = dequeue;
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }


// then to use it, it would be like this?
void foo() {
  semtab[5].enqueue(6);
}

Use 采用

static struct {
  int pid;
  int queue[MAXPROCS];

  void (*fncPtr_enqueue)(int); // This defines a member fncPtr_enqueue
  int (*fncPtr_dequeue)();     // Note that you had fcnPtr_ in your post.
                               // I have fncPtr_ here.
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }

Each object in semtab that needs to have valid function pointers needs to be updated. semtab中需要具有有效功能指针的每个对象都需要更新。

semtab[0].fncPtr_enqueue = enqueue;
semtab[0].fncPtr_dequeue = dequeue;

You could use: 您可以使用:

static struct
{
    int pid;
    int queue[MAXPROCS];
    void (*enqueue)(int);
    int (*dequeue)(void);
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue(void) { /* code */ }

void foo(void)
{
    semtab[5].enqueue(6);
}

Changes include: 更改包括:

  1. Systematic names for structure member pointers (instead of mixed fncPtr and fcnPtr prefixes). 结构成员指针的系统名称(而不是混合的fncPtrfcnPtr前缀)。
  2. No attempt to initialize in the structure definition. 没有尝试在结构定义中初始化。
  3. Add void to function prototypes to indicate no arguments. 在函数原型中添加void以指示没有参数。 In C (and in contrast to C++), an empty pair of brackets (parentheses) means "a function taking an undefined number of arguments, but not one which has a variable argument list with ... ellipsis". 在C语言中(与C ++相反),一对空括号(括号)表示“一个函数带有未定义数量的参数,但没有一个带有可变的参数列表,并带有...省略号”。
  4. Because of (1), the original invocation is OK. 由于(1),原始调用就可以了。 (With the original code, you'd have needed semtab[5].fncPtr_enqueue(6); — or even (*semtab[5].fncPtr_enqueue)(6); ) (使用原始代码,您需要semtab[5].fncPtr_enqueue(6); —甚至是(*semtab[5].fncPtr_enqueue)(6);

You would still have to ensure that the function pointers in the table are all initialized. 您仍然必须确保表中的函数指针都已初始化。

With GCC and C99 or C11 compilation, you could initialize the array using: 使用GCC和C99或C11编译时,可以使用以下方法初始化数组:

static struct
{
    int pid;
    int queue[MAXPROCS];
    void (*enqueue)(int);
    int (*dequeue)(void);
} semtab[MAXSEMS] =
{
    [0 ... MAXSEMS-1] = { .enqueue = enqueue, .dequeue = dequeue }
};

The [0 ... MAXSEMS-1] part is a GCC extension. [0 ... MAXSEMS-1]部分是GCC扩展。 Observe that a space is required after the 0 to avoid problems with the 'maximal munch' rule. 请注意,在0后面必须有一个空格,以免出现“最大删节”规则。

As JS1 mentioned in the comments, it's actually pretty pointless to do this with the example you have, as you're not achieving anything with the indirection if you're not going to vary the value of those pointers. 正如注释中提到的JS1一样,用您的示例执行此操作实际上是毫无意义的,因为如果您不打算更改这些指针的值,则无法通过间接实现任何操作。

That being said, here's an example using a stack (because the logic is easier than a queue, and this is a simple example). 话虽如此,这是一个使用堆栈的示例(因为逻辑比队列更容易,并且这是一个简单的示例)。 Note that you must pass a pointer to the stack to each of your member functions, because while C++ member functions have an implicit this argument, C functions never do. 请注意,必须将指向堆栈的指针传递给每个成员函数,因为C ++成员函数具有隐式的this参数,而C函数则永远不会这样做。 You also need to give your struct a name, otherwise you won't be able to refer to it in the abstract, which you need to do. 您还需要给您的struct一个名字,否则您将不能在抽象中引用它,您需要这样做。

This program uses the same struct to implement two variations of a stack, one normal one, and one which unnecessarily shouts at you when you push or pop: 该程序使用相同的struct来实现堆栈的两种变体,一种是普通的,另一种是在您按下或弹出时不必要地对您大喊:

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

enum {
    STACKSIZE = 1024
};

struct stack {
    int stack[STACKSIZE];
    size_t top;
    void (*push)(struct stack *, int);
    int (*pop)(struct stack *);
    void (*destroy)(struct stack *);
};

void stack_push(struct stack * this, int i)
{
    if ( this->top == STACKSIZE ) {
        fprintf(stderr, "Queue full!\n");
        exit(EXIT_FAILURE);
    }

    this->stack[this->top++] = i;
}

void stack_push_verbose(struct stack * this, int i)
{
    stack_push(this, i);
    printf("** PUSHING %d ONTO STACK! **\n", i);
}

int stack_pop(struct stack * this)
{
    if ( this->top == 0 ) {
        fprintf(stderr, "Stack empty!\n");
        exit(EXIT_FAILURE);
    }

    return this->stack[--this->top];
}

int stack_pop_verbose(struct stack * this)
{
    const int n = stack_pop(this);
    printf("** POPPING %d FROM STACK! **\n", n);
    return n;
}

void stack_destroy(struct stack * this)
{
    free(this);
}

struct stack * stack_create(void)
{
    struct stack * new_stack = malloc(sizeof * new_stack);
    if ( !new_stack ) {
        perror("Couldn't allocate memory");
        exit(EXIT_FAILURE);
    }

    new_stack->top = 0;
    new_stack->push = stack_push;
    new_stack->pop = stack_pop;
    new_stack->destroy = stack_destroy;

    return new_stack;
}

struct stack * stack_verbose_create(void)
{
    struct stack * new_stack = stack_create();
    new_stack->push = stack_push_verbose;
    new_stack->pop = stack_pop_verbose;

    return new_stack;
}

int main(void)
{
    struct stack * stack1 = stack_create();
    struct stack * stack2 = stack_verbose_create();

    stack1->push(stack1, 4);
    stack1->push(stack1, 3);
    stack1->push(stack1, 2);

    printf("Popped from stack1: %d\n", stack1->pop(stack1));

    stack2->push(stack2, 5);
    stack2->push(stack2, 6);

    printf("Popped from stack2: %d\n", stack2->pop(stack2));
    printf("Popped from stack1: %d\n", stack1->pop(stack1));
    printf("Popped from stack1: %d\n", stack1->pop(stack1));
    printf("Popped from stack2: %d\n", stack2->pop(stack2));

    stack1->destroy(stack1);
    stack2->destroy(stack2);

    return 0;
}

with output: 输出:

paul@horus:~/src/sandbox$ ./stack
Popped from stack1: 2
** PUSHING 5 ONTO STACK! **
** PUSHING 6 ONTO STACK! **
** POPPING 6 FROM STACK! **
Popped from stack2: 6
Popped from stack1: 3
Popped from stack1: 4
** POPPING 5 FROM STACK! **
Popped from stack2: 5
paul@horus:~/src/sandbox$ 

Note that we use the exact same struct stack for both types of stack - the differences between them are implemented by having the function pointers point to different functions in each case. 请注意,我们为两种类型的堆栈使用了完全相同的struct stack -它们之间的差异是通过使函数指针分别指向不同的函数来实现的。 The only visible difference to the user is that one is created with stack_create() , and the other is created with stack_create_verbose() . 对用户而言唯一可见的区别是,一个是使用stack_create()创建的,另一个是使用stack_create_verbose()创建的。 In all other respects, they're used identically, so you can see the polymorphism at work. 在所有其他方面,它们的用法相同,因此您可以看到工作中的多态性。

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

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