Показать полную графическую версию : [решено] Запись значения в объединение
По Си проходим тему объединения, возник вопрос, для того, чтобы ввести значение объединения, надо ли предварительно знать тип этого значения? т. е. можно ли делать так
union mnz
{
int chislo;
char bukva;
};
union mnz u;
а потом
u='g';
и значение объединения будет g, или можно только так
u.bukva='g';
какое вообще преимущество даёт применение объединений, если можно, с примером?
Hector, нет нельзя. Нужно указать элемент объедения, которому присваивается значение -> u.bukva='g';.
У объединения нет такого понятия как значение, есть значение его элементов. Именно значение, а не значения. Программисту нужно следить за тем, с каким элементом сейчас работа в объединении.
union используется преимущественно для экономии памяти.
Так же в качестве возвращаемого параметра функции удобно использовать, как некий интерфейс: если функция будет возвращать новый тип, его достаточно будет указать в объединении.
возьмем код из второго поста этой темы Поиск текста в файлах (http://forum.oszone.net/post-1192322.html#post1192322)
в функции 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 объединений поисковик ничего не нашёл. Совет использования его там вычитал в книге Юрова посвященной Ассемблеру.
хорошо, а существует способ проверить при выводе, какое сейчас значение у объединения, допустим мне нужно вывести значение u, но как узнать в данный момент там цифра (int) или буква (char)?
А если так?
#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;
}
ganselo, не совсем понял, можно комментарии (только учусь :) )
Hector, мне такой не известен, но для мониторинга\отладки можно через printf "позванивать" содержимое элементов объединения - printf("chislo - %i\tbukva-%c", u.chislo, u.bukva); и по выводу ориентироваться. Но правильнее смотреть по коду, к какому элементу последний раз было присваивание.
ganselo, смущает строчка memset(&t, 'g', sizeof(t) + sizeof(int)); при установки памяти выйдем на sizeof(int)) за пределы объединения?
Размер объединения в данном случаи int (по наибольшему размеру типа элемента объединения).
Но правильнее смотреть по коду, к какому элементу последний раз было присваивание »
есть такая задача:
Необходимо обеспечить выполнение следующих действий (операций):
1) ввод информации в массив структур;
2) просмотр на экране содержимого массива структур в виде таблицы;
3) одним из элементов структуры является объединение;
Исходные данные:
Меню
Название блюда
Стоимость блюда
Объединение
Калорийность блюда
Наличие полезных веществ
т. е. когда я буду выводить данные, как мне определить какое из возможных значений объединения надо отображать?
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 выводим
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.