Как использовать объединение на языке C

#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. 😉