объединение значения и указателя на функцию - PullRequest
0 голосов
/ 04 февраля 2019

Я борюсь с использованием союзов.Почему я не могу передать указатель функции туда, где будет объединение?Любая помощь будет принята с благодарностью.

Редактировать: удален typedef

#include <stdio.h>

union U {
    int(*fnPtr)(int);
    int i;
};

enum E {
    OPTION_0 = 0,
    OPTION_1 = 1
};

int multiply_by_two (int x) {
    return 2 * x;
}

int f (int x, enum E e, union U u) {
    switch (e) {
        case OPTION_0:
            /* Return the sum */
            return x + u.i;
        case OPTION_1:
            /* Return 2 * x */
            return u.fnPtr (x);
    }
}

int main (void) {
    int a;
    scanf ("%d", &a);
    int b = f (a, OPTION_1, &multiply_by_two);
    printf ("%d\n", b);
    return 0;
}

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

В основной функции попробуйте следующее:

int main()
{
  ...
  union U myUnion;
  myUnion.fnPtr = &multiply_by_two;
  int b = f (a, OPTION_1, myUnion);
  ...
}

А также, определение объединения неверно, вам необходимо удалить typedef.

0 голосов
/ 04 февраля 2019

Просто добавьте к другим ответам: это обычно называется вариантом типа данных, и имеет смысл сохранить тип enum в struct вместе с union, так как вы будете передавать его по всемвремя в любом случае.

Так что я бы рекомендовал поместить оба в struct:

enum var_type
{
    VAR_INT = 0,
    VAR_FUNC = 1
};

struct variant
{
    // contains the type of the stored value
    enum var_type type;

    // contains the actual value
    union {
        int(*fnPtr)(int);
        int i;
    };    
};

И тогда у вас могут быть отдельные функции для создания каждого подтипа, для более простой реализации:

// wrap the int value in the variant struct
struct variant variant_create_int(int i)
{
    return (struct variant){ .type = VAR_INT, .i = i };
}

// wrap the functino pointer in the variant struct
struct variant variant_create_func(int(*fnPtr)(int))
{
    return (struct variant){ .type = VAR_FUNC, .fnPtr = fnPtr };
}

То есть ваш main будет делать что-то вроде:

// create variant of type 'VAR_FUNC'
struct variant var = variant_create_func(&multiply_by_two);

и просто передаст структуру var вперед.

0 голосов
/ 04 февраля 2019

Во-первых, это определение недопустимо:

union U {
    typedef int(*fnPtr)(int);
    int i;
};

Вы не можете иметь typedef внутри struct или union.Удаление typedef даст вам правильное определение:

union U {
    int(*fnPtr)(int);
    int i;
};

Вторая проблема здесь:

int b = f (a, OPTION_1, &multiply_by_two);

Функция f ожидает union U, но вы передаетеэто int (*)(int).Эти типы не совместимы.Тот факт, что у союза есть член этого типа, не означает, что вы можете использовать этот тип везде, где бы вы использовали союз.Вам необходимо создать объединение, установить правильное поле и передать его функции.

union U u;
u.fnPtr = multiply_by_two;
int b = f (a, OPTION_1, u);
...