2015-02-15 3 views
2

Как создать указатель на функцию с STRUCT таблицы, такие какC функция массива структура указатель

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

Я думаю, что я понимаю, как сделать OO эквивалент в C, используя указатель на функцию с this post, но как я могу сделать с когда моя структура является массивом. Я все еще немного в синтаксисе.

Будет ли что-то вроде

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); 
} 
+0

Я не уверен, что вы действительно спрашиваете, не могли бы вы уточнить свой вопрос? –

+0

Вы должны объявить функции, прежде чем сможете их использовать. Вы не можете создавать инициализаторы в теле определения структуры. Используя стандарт C, вы не можете использовать количество повторов для инициализаторов, что является неприятностью. GCC предоставляет нестандартное расширение для поддержки повторных инициализаторов. –

+1

Вы должны использовать '(void)' для функции без аргументов; в C пустой список аргументов не формирует прототип, это означает, что любое количество параметров может соответствовать (и вызывать неопределенное поведение во время выполнения). –

ответ

1

Использование

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 */ } 

Каждый объект в semtab, который должен иметь действительные указатели функций необходимо обновить.

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

Это своего рода вопрос о noob. Скажем, я хочу ввести в очередь (5), queue [tail ++] = input. Когда я вызываю функцию, semtab [5] .enqueue (5), эта очередь будет иметь очередь semtab [5]? – Sugihara

+0

@Jack, это правильно. –

+1

Возможно, было бы неплохо дать 'enqueue()' некоторое представление о точно *, которая * очередь, которую вы хотите использовать. Сейчас это не имеет понятия. Вам нужно явно передать ему указатель на 'semtab [5]' s 'queue' или указатель на' semtab [5] 'себя. –

1

Вы могли бы использовать:

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); 
} 

Изменения включают в себя:

  1. Систематические названия для указателей членов структуры (вместо смешанных fncPtr и fcnPtr префиксов).
  2. Не пытайтесь инициализировать в определении структуры.
  3. Добавить void, чтобы использовать прототипы для указания аргументов. В C (и в отличие от C++) пустая пара скобок (скобки) означает «функция, принимающая неопределенное количество аргументов, но не та, которая имеет список переменных аргументов с ... эллипсисом».
  4. Из-за (1) исходный вызов в порядке. (С исходным кодом, вы бы нуждались semtab[5].fncPtr_enqueue(6); - или даже (*semtab[5].fncPtr_enqueue)(6);)

Вы все еще должны гарантировать, что указатели на функцию в таблице инициализированы.

С 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 } 
}; 

[0 ... MAXSEMS-1] часть является расширением GCC. Обратите внимание, что после 0 требуется пространство, чтобы избежать проблем с правилом «максимального munch».

1

Как упоминалось в комментариях JS1, на самом деле это довольно бессмысленно делать с примером, который у вас есть, поскольку вы не достигаете ничего с косвенностью, если вы не собираетесь изменять значение этих указателей.

Это пример использования стека (потому что логика проще, чем очередь, и это простой пример). Обратите внимание, что вы должны передать указатель на стек каждой из своих функций-членов, потому что в то время как функции-члены C++ имеют неявный аргумент this, функции C никогда не выполняются. Вы также должны указать свое имя struct, иначе вы не сможете обратиться к нему в реферате, который вам нужно сделать.

Эта программа использует тот же 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; 
} 

с выходом:

[email protected]:~/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 
[email protected]:~/src/sandbox$ 

Обратите внимание, что мы используем то же самое struct stack для обоих типов стека - различия между ними реализуются путем указания указателей функций на разные функции в каждом случае. Единственное видимое отличие от пользователя заключается в том, что он создан с stack_create(), а другой - с stack_create_verbose(). Во всех других отношениях они используются одинаково, поэтому вы можете увидеть полиморфизм на работе.

Смежные вопросы