Как использовать объединение в структуре и typedef для каждой структуры с различным типом объединения? - PullRequest
1 голос
/ 14 сентября 2011

Я хочу создать связанный список, но я хочу, чтобы поле данных было либо int, либо float.Я написал некоторый код, подобный следующему:

union int_or_float
{
    int int_member;
    float float_member;
};

struct node 
{
    union int_or_float data;
    struct node *next;
};

Я хочу написать что-то вроде:

typedef struct node item; 

, но как указать, какой тип в объединении мне нравится, чтобы элемент был?

Ответы [ 7 ]

3 голосов
/ 14 сентября 2011

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

Если вы напишите int_member, тогда он будет содержать int.

Если вы напишите float_member, он будет содержать число с плавающей точкой. (И если впоследствии вы прочитаете из int_member, то весь ад вырвется на свободу.)

2 голосов
/ 14 сентября 2011

Вам не нужно ничего "указывать". Вы просто сохраняете значение в соответствующем члене объединения.

Однако, похоже, что ваши структуры предназначены для использования в качестве узлов в некотором списке. Если ваш список должен содержать разные типы значений одновременно, то, конечно, вам нужно каким-то образом определить, какой тип содержит каждый элемент списка. Это можно сделать только вручную. То есть Вы несете ответственность за то, чтобы как-то хранить эту информацию внутри каждого элемента списка. Например, вы можете добавить поле type в вашу структуру

struct node 
{
    enum { INT, FLOAT } type;
    union int_or_float data;
    struct node *next;
};

...

struct node *p;

p = malloc(sizeof *p);
p->type = INT;
p->data.i = 42;
/* ... and add it to the list */

p = malloc(sizeof *p);
p->type = FLOAT;
p->data.f = 3.14;
/* ... and add it to the list */
1 голос
/ 14 сентября 2011

К тому времени, когда вы добавляете дополнительное хранилище и условные выражения для проверки, хранит ли объединение int или float, вы могли просто изменить поле на double, и тогда вы могли бы легко установить любое значение, которое подходит либо к int, либо к float, не беспокоясь о том, какой это тип (в большинстве реализаций, где int является 32-битным, а double - с двойной точностью IEEE 754). Я думаю, что это будет намного более чистый дизайн ...

0 голосов
/ 14 сентября 2011

вам может быть лучше хранить как float, так и int, а затем использовать функции присваивания, чтобы установить их правильные значения.класс может работать лучше для этого

struct node 
{
    int idata;
    float fdata;
    struct node *next;
    void setData(int data);  
    void setData(float data);
};

node::setData(int data)
{
    idata = data;
    fdata = (float)data;
}

node::setData(float data)
{
    idata = (int)data;
    fdata = data;
}
0 голосов
/ 14 сентября 2011

Вы можете добавить поле в структуру, указывающее, какой член объединения в настоящее время является действительным. Простой пример:

union int_or_float
{
    int int_member;
    float float_member;
};

struct node 
{
    union int_or_float data;
    bool int_is_valid;
    struct node *next;
};

(Предполагается, что у вас есть #include <stdbool.h>.)

Обратите внимание, что все зависит от вас, чтобы значение int_is_valid соответствовало последнему сохраненному вами значению, а также извлекать int_member, только если int_is_valid имеет значение true, и извлекать float_member, только если int_is_valid ложно.

На практике было бы яснее использовать enum, а не bool.

0 голосов
/ 14 сентября 2011

Это делается автоматически при доступе к данным.Объединение - это не что иное, как немного менее хитрый способ приведения указателя.

#include <stdio.h>

union number {
  int i;
  float f;
};

struct node {
  union number data;
  struct node *next;
};

typedef struct node item;

int main(void) {
  item myItem;

  myItem.data.i = 12; /* Now contains an int */
  myItem.data.f = 12.0; /* Now contains a float */
  printf("location of myItem.data is %p\n", &myItem.data);
  printf("location of myItem.data.f is %p\n", &myItem.data.f);  
  printf("myItem.data is %f\n", *(float *)(&myItem.data));
  printf("myItem.data.f is %f\n", myItem.data.f);
  printf("sizeof(myItem.data) is %lu\n", sizeof(*(float *)(&myItem.data)));
  printf("sizeof(myItem.data.f) is %lu\n", sizeof(myItem.data.f));

  return 0;
}

Это приведет к выводу

location of myItem.data is 0x7fff5fbff9f0
location of myItem.data.f is 0x7fff5fbff9f0
myItem.data is 12.000000
myItem.data.f is 12.000000
sizeof(myItem.data) is 4
sizeof(myItem.data.f) is 4

запуска / тестирования на Intel Mac с gcc версии 4.2..1 (Apple Inc., сборка 5659)

0 голосов
/ 14 сентября 2011

Вы хотели что-то вроде этого:

#include <stdio.h>

union int_or_float
{
    int int_member;
    float float_member;
};

struct node 
{
    union int_or_float data;
    struct node *next;
};

int main()
{

    typedef struct node item;

    item one;
    one.data.int_member = 10;

    item two;
    two.data.float_member = 10.f;

    printf("%d", one.data.int_member);
    printf("%f", two.data.float_member);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...