Указатели на функции подобного расположения разрешены в союзе? - PullRequest
1 голос
/ 26 февраля 2011

Следующий код компилируется и прекрасно работает с gcc.Но мне было интересно, определяется ли такой союз стандартом и работает ли он на всех компиляторах c одинаково.Я знаю, что это не сработает, если параметры этих функций не являются указателями и несовместимы друг с другом, но пока все параметры являются указателями, а количество параметров одинаково, проблем быть не должно, или?*

typedef struct node {
    unsigned long int key;
} node_t;

typedef struct node1 {
    unsigned long int key;
    char *str;
} node1_t;

typedef struct node2 {
    unsigned long int key;
    void *data;
} node2_t;

typedef struct node3 {
    unsigned long int key;
    int numbers[256];
} node3_t;


int compare(node_t *a, node_t *b) {

    printf("%ld ? %ld\n", c->key, d->key);
    return c->key == d->key;
}

struct comp {
    union {
        int (*c0) (node_t  *a, node_t  *b);
        int (*c1) (node1_t *a, node1_t *b);
        int (*c2) (node1_t *a, node2_t *b);
        int (*c3) (node1_t *a, node3_t *b);
        int (*c4) (node2_t *a, node1_t *b);
        int (*c5) (node2_t *a, node2_t *b);
        int (*c6) (node2_t *a, node3_t *b);
        int (*c7) (node3_t *a, node1_t *b);
        int (*c8) (node3_t *a, node2_t *b);
        int (*c9) (node3_t *a, node3_t *b);
    } are;
};


int main(int argc, char *argv[])
{
    node1_t a[] = {
        { 23477843258923UL, "Hello World" },
        { 10254892378892UL, "Hello Back" }
    };
    node2_t b[] = {
        { 83296783479803UL, NULL },
        { 52348237489832UL, (void *) &a[1] }
    };
    node3_t c[] = {
        { 91308823949203UL, { 3, 4, 5 } },
        { 17587832478823UL, {43, 43, 43, 86 } }
    };

    struct comp comp;
    comp.are.c0 = compare;

    comp.are.c1(&a[0], &a[1]);
    comp.are.c2(&a[1], &b[0]);
    comp.are.c3(&a[0], &c[1]);
    comp.are.c8(&c[1], &b[1]);
}

Ответы [ 3 ]

3 голосов
/ 26 февраля 2011

union действителен, но то, что вы делаете с ним, - нет.Вы не можете поместить что-то в union с одним типом, а затем использовать его с другим, как это делает конец main, если только эти типы не конвертируемы (спасибо @Christoph за этот комментарий).

1 голос
/ 26 февраля 2011

Независимо от того, действительно ли это верно, это ужасно безобразно.C имеет void * по причине.

Вот как это использовать:

int compare(void *a, void *b) {
    node_t *c = a, *d = b;
    printf("%ld ? %ld\n", c->key, d->key);
    return c->key == d->key;
}
0 голосов
/ 26 февраля 2011

Как сказал Иеремия, получение данных из объединения через члена, отличного от того, который вы использовали для помещения данных, является технически неопределенным поведением (но, вероятно, оно ближе всего к когда-либо стандартизированному неопределенному поведению).При этом, почему бы не переместить профсоюз туда, где вы действительно этого хотите?То, что вы хотите, это способ вызова функции, которая принимает 2 узла, которые могут иметь разные типы данных.Таким образом, вместо объединения указателей на функции, которые занимают 2 узла различных данных, переместите объединение туда, где на самом деле находятся разные данные: создайте функцию, которая принимает 2 узла, которые содержат объединение различных данных, то есть переместите объединение вкласс Node, поэтому один тип Node может содержать различные типы данных (AKA str / data / numbers) (хотя вы можете изменить int[256] на int* вэто случай).

Просто знайте, что сработает ли это или нет, будет * в зависимости от платформы, которую вы компилируете (в частности, соглашение о вызовах).

...