Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: sizeof union
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
sigmaN
Код
typedef union
{
    int    asHeader;

    struct
    {
        int                    header;
        int                    int1;
        int                    int2;
        int                    int3;
    }asInt3;

    struct
    {
        int                    header;
        char                     array[30];
    }asArray;
}my_union;

const int asInt3_size = sizeof(my_union.asInt3); // error: expected a ")" т.е. предлагает мне сделать sizeof(my_union);

А я бы очень хотел получить размеры каждого члена(или как там правильно его назвать) юниона.

Задумка такая: одной переменной описать три разных типа пакета, отличающиеся длиной и типом поля data.
Однако первые n байт всех трёх типов пакетов одинаковы и соответствуют заголовку(header).
Отправлять планируется в зависимости от надобности либо sizeof(my_union.asHeader); либо sizeof(my_union.asInt3) либо sizeof(my_union.asArray); байтов.
Header содержит поле, описывающее тип пакета, соответственно принемающая сторона всегда будет знать как трактовать пришедший пакет, сначала проанализировав это поле по my_union.asHeader;
К тому-же иногда(для подтверждения доставки) достаточно отправить просто asHeader.

Привлекательность состоит в том, что весь union займет в памяти столько месте, сколько необходимо для самого жирного члена(sizeof(asArray)) а AsHeader будет равен asArray.header и asInt3.header - потому как по идее &my_union_var.asHeader == &my_union_var.asInt3.header == &my_union_var.asArray.header

Верно ли последнее предположение по поводу header и как взять sizeof от члена union?
Или же поступить проще и определить структуры asHeader, asInt3, asArray отдельными typedef'ами, а union просто будет:
Код
typedef union
{
    asHeader_type    asHeader;
    asInt3_type    asInt3;
    asArray_type    asArray;
}my_union;

const int asInt3_size = sizeof(asInt3_type);


P.S. Ссылочку на стандарт С99 мне подкинули, но оказалось что сходу там ответ найти бывает очень сложно. smile.gif
GetSmart
Код
const int asInt3_size = sizeof(my_union.asInt3);

const int asInt3_size = sizeof(((my_union *)0)->asInt3);


Один из вариантов должон сработать. Проверять лень.

-------------
PS. отредактировано уже после нижестоящего поста.
sigmaN
Т.е. всё-таки рекомендуется пойти по второму пути и определить asInt3_type отдельным typedef? Этот вариант резервный smile.gif
Больше меня интересует почему не работает первоначальный вариант(первый codebox) и как выкрутиться без правки union.

added: да да, работает и так. const int asInt3_size = sizeof(((my_union *)0)->asInt3);
Просто меня сразу немного смутило, что вместо asInt3 было asInt3_type smile.gif

added later:Нда, Си мощная штука smile.gif))
rezident
Цитата(sigmaN @ Oct 15 2009, 01:07) *
Или же поступить проще и определить структуры asHeader, asInt3, asArray отдельными typedef'ами, а union просто будет:
Не люблю union-ы sad.gif Может я не совсем правильно понял, но вы ведь работаете с буфером, так? А кто вам мешает работать с буфером с помощью указателя? Причем указатель можно объявить любого из трех типов и соответственно работать со структурой именно того типа, который в данный момент нужен. Ну а с выбором наибольшего sizeof от каждой структуры у вас надеюсь нет проблем?
GetSmart
Цитата(sigmaN @ Oct 15 2009, 01:29) *
Т.е. всё-таки рекомендуется пойти по второму пути и определить asInt3_type отдельным typedef? Этот вариант резервный smile.gif

Не, я тут как бы опечатался. Хотел внутри sizeof() написать имя поля, а не его тип. Тип поля писать внутри структуры внутри sizoef() вообще бессмысленно.
sigmaN
Ну как сказать. можно и указатели, можно и разные типы. В функции можно передавать void *, а там уже делать с ним что хочешь.

А почему не любите? Я тут как-бы может быть слегка вдохновленный возможностями Си и разошелся маленько. В общем суть такова:
Код
/*
*    Размер пакета может меняться в зависимости от настройки алгоритма(размер блока, размер поля ID(публ. ключа))
*
*    Нам нужны пакеты двух типов
*    1.ID-пакет: используется для передачи ID абонентов и ID корпорации
*    2.Block-пакет: предназначен для транспорта данных длиной в 1 блок(хэш-функция, случайная выборка)
*    Но для унификации функций обработки пакетов яввел union ba05_net_packet
*/
enum conn_stages{ public_keys_interchange, random_sample_interchange, hash_interchange };//стадии соединения
enum packetTypes{ IDPacket, BlockPacket };
//заголовок у обоих типов пакетов общий, поэтому опишем его один раз
typedef struct
{
    enum packetTypes    packetType;    
    enum conn_stages    connStageID;
    unsigned            needACK    : 1;    //сообщает приёмнику, что в ответ на этот пакет нужно обязательно отправить ACK пакет
    unsigned            ACK        : 1;    //Признак пакета подтверждения. Если ACK==1 - все остальные поля не используются(кроме crc8,естественно)    
    unsigned             crc8     : 8;
}ba05_net_pktHeader;

//этот union позволяет использовать один тип данных(ba05_net_packet) для обоих типов пакетов.
typedef union
{
    ba05_net_pktHeader    header;                //иногда нужен _только_ заголовок пакета. К нему можно удобно обратиться :)
    struct
    {
        ba05_net_pktHeader    header;
        ba05_ID                master_ID;    
        ba05_ID                slave_ID;        
        ba05_ID                slave_corpID;    
    }asIDPacket;//1.ID-пакет: используется для передачи ID абонентов и ID корпорации
    struct
    {
        ba05_net_pktHeader    header;
        ba05_blockKey        data;
    }asBlockPacket;//2.Block-пакет: предназначен для транспорта данных длиной в 1 блок
}ba05_net_packet;

enum {     BlockPacketSize = sizeof(((ba05_net_packet *)0)->asBlockPacket),
        IDPacketSize = sizeof(((ba05_net_packet *)0)->asIDPacket),
        HeaderPacketSize = sizeof(((ba05_net_packet *)0)->header) };


По-моему достаточно элегантно выходит.
Но оценить объективно свой подход бывает достаточно сложно.

Поэтому реквестирую кАменты знатоков smile.gif
KRS
Я бы в описаниях пакетов использовал типы с явным указанием количества бит!
А то у вас при компилляции для разных процессоров - структуры будут разные!
sigmaN
Взаимодействие систем по этому протоколу будет производиться ТОЛЬКО в сетях, состоящих из девайсов с одинаковыми типами процессоров.
Более того, типы данных ba05_ID и ba05_blockKey определены выше и именно с явным указанием размеров.
Единственное тут будет проблема с
unsigned needACK : 1; //сообщает приёмнику, что в ответ на этот пакет нужно обязательно отправить ACK пакет
unsigned ACK : 1; //Признак пакета подтверждения. Если ACK==1 - все остальные поля не используются(кроме crc8,естественно)
unsigned crc8 : 8;

т.к. паковаться битовые поля будут в int, размер которого действительно может быть различным.
added: нда, похоже и enum тоже implementation defined и могут быть те-же проблемы int
zltigo
Для начала, union притянут за уши. Начните плясать от:
Код
typedef struct ba05_net_packet
{
    ba05_net_pktHeader    header;    //иногда нужен _только_ заголовок пакета. К нему можно удобно обратиться :)
union{
    asIDBody;
    ba05_blockKey;
};
}ba05_net_packet;

Структуру по любому паковать.
sigmaN
Отлично!
Благодарю.

Действительно, немножко не с той стороны подошел smile.gif

Хорошо.
Тут вот более глубоко задумался над typedef....
видимо ещё паскалевский стиль мышления заставляет воспринемать структуру как новый тип данных(ну и, естественно, сразу в голову приходит typedef)

Так вот, собственно, так-же известно, что ту-же структуру можно определить без typedef, а потом точно так-же определять структурные переменные.
Вопрос в том, чем отличается
Цитата
struct my_struct
{
int field1;
int fieeld2;
};
//а потом
my_struct my_struct_var;
от
Цитата
typedef struct
{
int field1;
int fieeld2;
}my_struct;
//а потом
my_struct my_struct_var;

Разница ведь только в области видимости?
т.е. typedef действительно глобальный, а тег структуры(при объявлении по первому методу) будет иметь область видимости ограниченную файлом.
Я ничего не упустил?
А то наплодил typedef а теперь вот задумался, что может быть абсолютно напрасно smile.gif
KRS
Цитата(sigmaN @ Oct 15 2009, 02:14) *
Разница ведь только в области видимости?

Если вы используете С++ то разницы нет!
А если С, то при каждом объявлении надо будет писать:
struct my_struct my_struct_var;
вот что бы не писать слово struct каждый раз и используют typedef.
sigmaN
Понятно. Значит буду продолжать typedef. В принципе он мне нравится
defunct
Цитата(sigmaN @ Oct 15 2009, 10:24) *
Понятно. Значит буду продолжать typedef. В принципе он мне нравится


Тогда еще одит "trick" на примере приведенном zltigo

Код
typedef struct tag_ba05_net_packet
{
    struct tag_ba05_net_packet *pNextPacket;  // иногда полезно когда пакеты связаны

    ba05_net_pktHeader    header;    //иногда нужен _только_ заголовок пакета. К нему можно удобно обратиться :)
    union{
        asIDBody;
        ba05_blockKey;
    };
} ba05_net_packet_t, *ba05_net_packet_ptr_t;


Сразу и список пакетов формировать можно и указатель на пакет объявлен.
GetSmart
Цитата(defunct @ Nov 4 2009, 05:54) *
Код
    union{
        asIDBody;
        ba05_blockKey;
    };

Это что такое? Нетипизированные поля?
defunct
Цитата(GetSmart @ Nov 4 2009, 23:56) *
Это что такое? Нетипизированные поля?

Этот кусочек я отцитировал.

Думаю там предполагались структуры:
Код
union
{
    zzz_t  zzz;
    xxx_t  xxx;
}
sigmaN
Сейчас так:
Код
struct ba05_net_pktHeader
{
    uint16_t    packetType    : 3;    
    uint16_t    connStageID    : 3;  
    uint16_t    needACK        : 1;    
    uint16_t    ACK            : 1;    
    uint16_t    crc8            : 8;
};
//описание поля data для пакета IDPacket
struct ba05_net_IDPacket_data
{
    ba05_ID                public_ID;    
    ba05_ID                corp_ID;    
};

typedef struct
{
    struct ba05_net_pktHeader             header;
    union
    {
        struct ba05_net_IDPacket_data        asIDPacket;
        ba05_blockKey                    asBlockPacket;
    }data;
}ba05_net_packet;
Цитата
Сразу и список пакетов формировать можно и указатель на пакет объявлен.
Да вроде как и не требуется особо... Этими пакетами система кидается только на этапе синхронизации(соединения)...Это всё оборачивается ещё одним протоколом, который как раз и занимается списками пакетов/разбором полётов и т.д..
Но на заметку взял сам принцип, спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.