Как передать указатель объединения в качестве параметра в C? а что внутри союза? - PullRequest
3 голосов
/ 06 октября 2011

У меня есть вопрос об объединении в ц.Следующий код на стороне сервера, мы получаем Signal2 со стороны клиента, в сервисной функции, могу ли я проверить тип сигнала следующим образом: data_p->header.type?и в случае с переключателем, как я могу передать параметр в функцию printInfo (), параметром которого является указатель на объединение, как передать?И последний вопрос - указатель на объединение, указать на что?и что находится внутри объединения, когда эти три структуры распределены, как они могут вписаться в объединение (с размером большой структуры)?

   union
    {
        Header  header;
        Signal1 signal1;
        Signal2 signal2;
    } Data;

struct Header 
{   
    int type:
    int protocol;
    int clientId;
    int serverId;
};


struct Signal1
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    char[80] something;
};


struct Signal2
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    int[100] something;
};


void service(Data* data_p) {

    switch(data_p->header.type) {
        case 1:
            printInfo(&data_p->header);
        case 2:
            printInfo(data_p->header);
        case 3:
            data_p->signal2->something[5];
    }   
}


void printInfo(Data* data_p) 
{
    data_p->header.primitive;
}

Ответы [ 6 ]

2 голосов
/ 06 октября 2011

В вашем примере похоже, что вы хотите полагаться на тот факт, что поля type, protocol, clientId, serverId из Header, Signal1, Signal2 будут выровнены одинаково. Но ничто в стандарте C или C ++ не гарантирует, что AFAIK. Так что это, вероятно, будет работать с большинством компиляторов Си, но это хак, где такой хак не нужен.

Кажется, что было бы лучше сделать следующее:

struct Header 
{
    int type:
    int protocol;
    int clientId;
    int serverId;
};

struct Signal1
{
    char something[80];
};

struct Signal2
{
    char something[100];
};

struct Message
{
    struct Header header;
    union
    {
        struct Signal1 signal1;
        struct Signal2 signal2;
    } payload;
};

Что касается вашего последнего вопроса, если я правильно понимаю, объединению выделено достаточно памяти для наибольшего из его членов, и выровнено по самой строгой из границ его членов, и в любой момент времени содержатся действительные данные для одного из это члены (но ничего не указывает на то, что является правильным). И указатель на объединение является адресом начала этой области памяти.

0 голосов
/ 06 октября 2011

вам нужно специализировать printinfo ()

как void printinfo (Заголовок *)

void printinfo (Signal1 *)

void printinfo (Signal2 *)

затем передайте его, как в случае 2: ​​printInfo (& data_p-> signal1);// передать правый член объединения в правильную функцию

, поэтому на самом деле вы не передаете объединение, вы передаете данные внутри объединения.

второй вопрос: объединения не являются структурами.союзы имеют размер самого большого члена.Вы должны прочитать размер объединения в C / C ++

удачи

0 голосов
/ 06 октября 2011

Синтаксис доступа к членам объединения очень похож на синтаксис, используемый для доступа к членам структуры. Один использует. оператор для доступа к полю объединения через простое объединение и -> для доступа к полю объединения через указатель на объединение. Предполагая объединение данных в вашем примере:

Data v;
Data *p = &v;
int ftype;

ftype = v.header.type;
ftype = p->header.type;

Что касается параметра для printinfo, тип параметра, указанный в вашем коде, является правильным, это должен быть указатель на Данные. Однако код внутри printInfo неверен, как указано в другом месте. Я ожидаю, что он будет содержать переключатель в поле типа заголовка, аналогичный тому, который указан в методе службы, как показано ниже:

void printInfo(Data* data_p) 
{
    printf("Type %d, protocol %d, clientId %d, serverId %d ",
         data_p->header.type, data_p.header.protocol,
         data_p->header.clientId, data_p->header.serverId);

    switch(data_p->header.type) {
        case 1:
            // Signal 1
            printf("signal 1 (string): %s", data_p->signal1.something);
        case 2:
            // Signal 2
            printf("signal 2 (int array): %d", data_p->signal2.something[0]);
        // and so on
    }
    printf("\n");
}

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

Программист должен отслеживать, какой из возможных элементов был добавлен в объединение, и обращаться к нему соответствующим образом. В объединении данных в вашем примере для этого используется поле header.type.

0 голосов
/ 06 октября 2011

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

 switch(data_p->header.type) {
     case 1:
         printInfo(data_p);
     case 2: //unknown type?
         printInfo(data_p);
     case 3: // type is obviously signal2
         data_p->signal2->something[5];
 }   

Так что да, вы можете проверить с помощью data_p-> header.type.мне кажется, что вы могли бы немного переписать код, чтобы сделать его более очевидным

enum { 
  HEADER_TYPE  = 1, // fill in the correct type numbers here to match the documentation
  SIGNAL1_TYPE = 2,
  SIGNAL2_TYPE = 3
};
switch(data_p->header.type) {
    case 1:
        printInfo(data_p);
    case 2: //unknown type?
        printInfo(data_p);
    case SIGNAL2_TYPE: // type is obviously signal2
        data_p->signal2->something[5];
}   

другая вещь, которую я заметил в заголовке printInfo, не имеет переменной примитив из оператора switch, который вы бы сделалиДля правильного вызова используйте printInfo(data_p).

Самое важное здесь заключается в том, что программист должен убедиться, что переменная типа всегда установлена ​​на правильное значение, соответствующее правильной структуре части объединения,т. е. если структура представляет собой сигнал1, его 1, а если это сигнал2, то его 2 и т. д.

Но использование объединения здесь совершенно бесполезно, поскольку все поля идентичны, кроме последнего, а заголовокочевидно предназначенный для доступа к общим полям.

struct Header
{
  int type:
  int protocol;
  int clientId;
  int serverId;
};

struct Signal1
{
  struct Header header;
  int[80] something;
};

struct Signal2
{
  struct Header header;
  int[100] something;
};

enum { 
  SIGNAL1_TYPE = 0,
  SIGNAL2_TYPE
};

void service(struct Header* data_p) {

  switch(data_p->header.type) {
    default:
        printInfo(data_p);
      break;
    case SIGNAL1_TYPE:
        /* your code here */
        call_func( (struct Signal1 *) data_p );
      break;
    case SIGNAL2_TYPE:
        /* your code here */
        call_func( (struct Signal2 *) data_p );
      break;
  }   

}

0 голосов
/ 06 октября 2011

Что-то вроде

enum{Header,Signal1,Signal2} type = Header;

....
union Data
{
    Header header;
    Signal1 signal1;
    Signal2 signal2;
};

struct Packet
{
    type data_type; // points to one of Header, Signal1 or Signal2
    union Data data;
};

может быть хорошим способом передачи указателя на то, что содержит объединение.

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

0 голосов
/ 06 октября 2011

Я думаю, что ваше объявление объединения - это та часть, которая не работает должным образом.

Попробуйте выполнить следующее.

union Data
{
    Header  header;
    Signal1 signal1;
    Signal2 signal2;
};

Это должно сделать тип объединения с именем Dataвместо одной переменной анонимного типа объединения.

Отсюда вы сможете получить доступ к Header, даже если передали объект Signal2 через data_p->header.Type.

...