Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   [решено] Запись значения в объединение (http://forum.oszone.net/showthread.php?t=191530)

Hector 18-11-2010 01:07 1545333

Запись значения в объединение
 
По Си проходим тему объединения, возник вопрос, для того, чтобы ввести значение объединения, надо ли предварительно знать тип этого значения? т. е. можно ли делать так
Код:

union mnz
{
  int chislo;
  char bukva;
};

union mnz u;

а потом
Код:

u='g';
и значение объединения будет g, или можно только так
Код:

u.bukva='g';
какое вообще преимущество даёт применение объединений, если можно, с примером?

Admiral 18-11-2010 02:26 1545365

Hector, нет нельзя. Нужно указать элемент объедения, которому присваивается значение -> u.bukva='g';.
У объединения нет такого понятия как значение, есть значение его элементов. Именно значение, а не значения. Программисту нужно следить за тем, с каким элементом сейчас работа в объединении.

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

Например,
возьмем код из второго поста этой темы Поиск текста в файлах
в функции WinMain из всего множества объявлена переменная wcl типа WNDCLASS (это структура) и переменная msg типа MSG (тоже структура). Особенности использования первой таковы, что нужда в ней отпадает (в данном примере в частности) сразу же после использовании в функции RegisterClass. Вторая же напротив, нужна до окончания программы. Было бы логично использовать не нужную больше переменной память, и объединения тут поможет.
Для этого объявляем нечто вроде
Код:

        union sharMem
        {
                WNDCLASS wcl;
                MSG msg;
        } sM;

и в соответствии с правилами использования элементов объединения используем.
Вместо
Код:

        wcl.style = 0;
        wcl.lpfnWndProc = WindowFunc;
        wcl.cbClsExtra = 0;
//...
if (!RegisterClass (&wcl))
//...
        while(GetMessage(&msg, NULL, 0, 0) > 0)
        {
                TranslateMessage (&msg);
//...

будет
Код:

        sM.wcl.style = 0;
        sM.wcl.lpfnWndProc = WindowFunc;
        sM.wcl.cbClsExtra = 0;
//...
if (!RegisterClass (&sM.wcl))
//...
        while(GetMessage(&sM.msg, NULL, 0, 0) > 0)
        {
                TranslateMessage (&sM.msg);
//...


В примере выше использования union сэкономило 28 байт, которые не выделили для переменой типа MSG, так как последняя разместилась в памяти ранее занимаемой переменной типа WNDCLASS (это чуть больше 40 байт). Про такое использование в WinMain объединений поисковик ничего не нашёл. Совет использования его там вычитал в книге Юрова посвященной Ассемблеру.

Hector 18-11-2010 02:47 1545369

хорошо, а существует способ проверить при выводе, какое сейчас значение у объединения, допустим мне нужно вывести значение u, но как узнать в данный момент там цифра (int) или буква (char)?

ganselo 18-11-2010 02:55 1545373

А если так?
Код:

#include <string.h>
#include <stdio.h>

union test
{
    int in;
    char ch;
};

union test t;

int main()
{
    memset(&t, 'g', sizeof(t) + sizeof(int));
   
    printf("%c", t.ch);
    return 0;
}


Hector 18-11-2010 02:56 1545374

ganselo, не совсем понял, можно комментарии (только учусь :) )

Admiral 18-11-2010 03:00 1545375

Hector, мне такой не известен, но для мониторинга\отладки можно через printf "позванивать" содержимое элементов объединения - printf("chislo - %i\tbukva-%c", u.chislo, u.bukva); и по выводу ориентироваться. Но правильнее смотреть по коду, к какому элементу последний раз было присваивание.

ganselo, смущает строчка memset(&t, 'g', sizeof(t) + sizeof(int)); при установки памяти выйдем на sizeof(int)) за пределы объединения?
Размер объединения в данном случаи int (по наибольшему размеру типа элемента объединения).

Hector 18-11-2010 05:10 1545390

Цитата:

Цитата Admiral
Но правильнее смотреть по коду, к какому элементу последний раз было присваивание »

есть такая задача:
Необходимо обеспечить выполнение следующих действий (операций):
1) ввод информации в массив структур;
2) просмотр на экране содержимого массива структур в виде таблицы;
3) одним из элементов структуры является объединение;
Исходные данные:
Меню
  • Название блюда
  • Стоимость блюда
  • Объединение
    • Калорийность блюда
    • Наличие полезных веществ

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

Admiral 18-11-2010 14:44 1545675

Hector в таком случаи в структуре нужно завести ещё одну переменную, определённую как enum, для того что б контролировать к какому полю объединения было обращение.
Код:

enum PlatterKPD {CALORIE, UTILITY};

struct{
        PlatterKPD pKPD;
//...
        union
        {
                /*Калорийность блюда;
                Наличие полезных веществ;*/
        };
}PlatterInfo;
//...
//для ввода интересуемся: продукт только калориен или есть ещё полезные вещества?
//соответственно заполняем PlatterInfo.pKPD как CALORIE или UTILITY
switch(PlatterInfo.pKPD)
{
        case CALORIE: /*scanf(“%s”, &PlatterInfo.Калорийность блюда);*/ break;
        case UTULITY: /*scanf(“%s”, &PlatterInfo.Наличие полезных веществ);*/ break;
        case default:
}
//при выводе так же через switch выводим



Время: 23:53.

Время: 23:53.
© OSzone.net 2001-