Использование двух разных структур для одних и тех же данных - PullRequest
0 голосов
/ 03 апреля 2012

Мне нужно перенести UUID из кода C ++ в код C, который будет работать на адаптере на базе Intel 8051.Я определил следующую структуру для представления UUID наиболее переносимым способом:

struct UUID {
    unsigned char data1[4];
    unsigned char data2[2];
    unsigned char data3[2];
    unsigned char data4[8];
};

Что ж, с этой структурой байтовых массивов не очень удобно работать в C ++, поэтому я определил промежуточный вспомогательный класс следующим образом:

#include <stdint.h> // #include <cstdint> in C++0x

class UUIDAssign {
public:
    uint32_t data1;
    uint16_t data2;
    uint16_t data3;
    uint64_t data4;

    operator UUID() const
    {
        UUID uuid(*((UUID*)this));
        return uuid;
    }    
};

Таким образом, я могу написать что-то вроде:

UUIDAssign assign1 = {0x80DFDD28, 0xF033, 0xB027, 0xCDD2078FC78A};
UUID uuid1 = assign1;

Я не вижу другого способа удобно инициализировать структуру UUID некоторым значением.Ну, инициализация его из строкового представления является ИМХО сомнительным вариантом.

Вопросы:

  1. Неправильно ли то, как я реализовал инициализацию UUID через промежуточный вспомогательный класс?Можете ли вы дать мне несколько предложений?
  2. Как насчет заполнения?Может ли это повлиять на данные, передаваемые в UUID из UUIDAssign?

Ответы [ 2 ]

1 голос
/ 03 апреля 2012

Union - ваш друг:

#ifdef __CPLUSPLUS
    #include <cstdint>
    #include <cstdio>
#else
    #include <stdint.h>
    #include <stdio.h>
#endif

union UUID {
    struct {
        uint32_t data1;
        uint16_t data2;
        uint16_t data3;
        uint64_t data4;
    } cpp;
    struct {
        unsigned char data1[4];
        unsigned char data2[2];
        unsigned char data3[2];
        unsigned char data4[8];
    } c;
};

int main() {
    UUID uuid = {0x80DFDD28, 0xF033, 0xB027, 0xCDD2078FC78A};

    printf("%u\n%x%x%x%x\n", uuid.cpp.data1, uuid.c.data1[3], uuid.c.data1[2], uuid.c.data1[1], uuid.c.data1[0]);

    return 0;
}

, который выводит (в младшем порядке, обратите внимание на обратную печать второго значения):

2162154792
80dfdd28

Порядок, в котором вы должныдоступ к подструктуре "c" зависит от машины .

1 голос
/ 03 апреля 2012

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

Кроме того, написанный вами код нарушает строгие правила псевдонимов C ++. Хотя ваш тип UUID содержит только массивы символов, он равен , а не массиву символов. Поэтому нельзя полностью исключить возможность возникновения проблем с оптимизатором (в форме неверно написанного кода).

Если вам не нужно, чтобы ваш класс UUID был POD, самым простым решением был бы конструктор для UUID, подобный этому:

struct UUID {
    unsigned char data1[4];
    unsigned char data2[2];
    unsigned char data3[2];
    unsigned char data4[8];
    UUID(uint32_t d1, uint16_t d2, uint16_t d3, uint64_t d4)
    {
      data1[0] = d4 & 0xff;
      data1[1] = (d4 >> 8) & 0xff;
      data1[2] = (d4 >> 16) & 0xff;
      data1[3] = d4 >> 24;
      // etc.
    }
};

Тогда вы можете определить свой объект UUID как

UUID uuid(0x80DFDD28, 0xF033, 0xB027, 0xCDD2078FC78A);

Если ваш объект UUID должен быть POD, вы можете сделать это следующим образом:

struct UUID {
    unsigned char data1[4];
    unsigned char data2[2];
    unsigned char data3[2];
    unsigned char data4[8];
};

struct UUIDAssign: UUID
{
    UUIDAssign(uint32_t d1, uint16_t d2, uint16_t d3, uint64_t d4)
    {
      data1[0] = d4 & 0xff;
      data1[1] = (d4 >> 8) & 0xff;
      data1[2] = (d4 >> 16) & 0xff;
      data1[3] = d4 >> 24;
      // etc.
    }
};

и инициализировать так:

UUID uuid = UUIDAssign(0x80DFDD28, 0xF033, 0xB027, 0xCDD2078FC78A);
...