#c #unions
#c #объединения
Вопрос:
У меня есть вопрос о объединении на языке C. Переменные, объявленные в объединении, будут совместно использовать одну и ту же память, хорошо, я понимаю. например,
union student {
int i;
int j;
}x;
как мы могли бы получить доступ к i и j?
если у нас есть: x.i = 1;
и тогда мы printf("%d",j);
что произойдет? ошибка компилятора?
Хорошо, тогда как насчет следующего случая:
union student {
int i;
float j;
}x;
если мы присвоим x.i = 2;
каково значение x.j?
Комментарии:
1. Нет, он не будет компилироваться, если вы не имели в виду
print("%s", x.j);
2. @ratzip Почему бы вам не попробовать это самостоятельно? 🙂
3. @fardjad, я пытался, но я не могу понять, как работает union!
4. @fardjad: С языком, в котором так много подводных камней, как C, изучение ограничений и семантики языка экспериментальным путем не является хорошим подходом.
5. @ratzip, мой ответ также касается вашего обновления. В некоторой степени, я обновлю сейчас более подробно.
Ответ №1:
Предполагая, что вы используете
printf("%d", x.j);
Вы увидите то же значение, которому вы присвоили x.i
, поскольку обе переменные занимают одну и ту же область памяти. Было бы нетипично присваивать обеим переменным один и тот же тип, как вы это сделали. Более типично, что вы бы сделали это, чтобы вы могли просматривать одни и те же данные, но как разные типы данных.
Представьте, например, что вы хотели бы рассматривать a double
как a double
и время от времени напрямую обращаться к битам (1s и 0s), которые представляют double, вы бы сделали это со следующим объединением.
union DoubleData
{
double d;
char b[8];
} x;
Теперь вы можете назначать / получать доступ к double напрямую через d
элемент или манипулировать тем же значением через 8 байт, которые представляют double в памяти.
Используя ваше недавнее обновление вопроса,
union student
{
int i;
float j;
}x;
Давайте сделаем предположение о вашей платформе, int
это 4 байта, а a float
— 4 байта. В этом случае при доступе x.j
вы будете манипулировать и обрабатывать 4 байта как double, при доступе x.i
вы будете манипулировать и обрабатывать 4 байта как целое число.
Итак, обе переменные накладываются друг на друга в одной и той же области памяти, но что будет отличаться, так это то, как вы интерпретируете битовый шаблон в этой области памяти. Имейте в виду, что любой 4-байтовый битовый шаблон является допустимым значением int, НО не любой 4-байтовый битовый шаблон является допустимым значением float.
Давайте сделаем другое предположение о вашей платформе, и значение int равно 2 байтам, а значение float равно 4 байтам. В этом случае при доступе x.i
вы будете манипулировать только половиной битового шаблона, на который накладывается значение float, потому что x.i
в этом случае наложение будет лишь частичным, x.j
поскольку x.j
охватывает больше байтов.
Комментарии:
1. И будьте осторожны, потому что безопасность этого зависит от реализации; фактически, это UB в языке.
2. Вы забыли ‘f’ в конце: printf(«%d», x.j);
Ответ №2:
Оба i
и j
будут совместно использовать одну и ту же память, поэтому все, что вы назначите одному, будет доступно и в другом элементе.
x.i = 1;
// x.j = 1
Ответ №3:
Это «неопределенное поведение».
Вы не можете записывать в i
, а затем читать из j
. Вы можете «использовать» только один из элементов одновременно.
Комментарии:
1. Иногда вам нужно использовать детали, специфичные для реализации. То, что это не переносимый C, не означает, что его следует отбросить во внешнюю тьму.
2. @David: Мне нравится видеть «необходимость» писать в
int
вunion
a и читать из другогоint
в том же самомunion
.3. В этом нет необходимости. Иногда это просто удобно. Не волнуйтесь, я просто веду свою личную битву в защиту специфичного для реализации, непереносимого C. 😉