В ранних версиях C все объявления структуры имели общий набор полей. Дано:
struct x {int x_mode; int q; float x_f};
struct y {int y_mode; int q; int y_l};
struct z {int z_mode; char name[20];};
компилятор, по сути, будет создавать таблицу размеров структур (и, возможно, выравнивания), а также отдельную таблицу имен, типов и смещений элементов структур. Компилятор не отслеживал, какие элементы принадлежат каким структурам, и позволял бы двум структурам иметь элемент с одинаковым именем, только если тип и смещение совпадают (как с элементом q
из struct x
и struct y
). Если бы p был указателем на какой-либо тип структуры, p-> q добавило бы смещение «q» к указателю p и извлекло бы «int» из полученного адреса.
Учитывая вышеупомянутую семантику, можно было написать функцию, которая могла бы выполнять некоторые полезные операции над несколькими типами структур взаимозаменяемо при условии, что все поля, используемые функцией, выровнены с полезными полями в рассматриваемых структурах. Это была полезная функция, и изменение C для проверки элементов, используемых для доступа к структуре, по типам рассматриваемых структур означало бы потерю его в отсутствие средства, имеющего структуру, которая может содержать несколько именованных полей по одному и тому же адресу. Добавление типов «объединение» в C помогло несколько заполнить этот пробел (хотя, не так, IMHO, как следовало бы).
Существенной частью способности профсоюзов заполнить этот пробел является тот факт, что указатель на член объединения может быть преобразован в указатель на любое объединение, содержащее этот член, а указатель на любой объединение может быть преобразован в указатель на любой участник. В то время как Стандарт C89 прямо не сказал, что приведение T*
непосредственно к U*
было эквивалентно приведению его к указателю на любой тип объединения, содержащему как 1013 *, так и U
, а затем приведение к U*
, определенное поведение последней последовательности приведения не будет затронуто используемым типом объединения, и в стандарте не указана какая-либо противоположная семантика для прямого приведения от T
до U
. Кроме того, в случаях, когда функция получает указатель неизвестного происхождения, поведение записи объекта с помощью T*
, преобразования T*
в U*
и последующего чтения объекта с помощью U*
будет эквивалентно записи объединение через член типа T
и чтение как тип U
, что в некоторых случаях будет определено стандартом (например, при доступе к элементам Common Initial Sequence) и определено реализацией (а не неопределено) для остальных. В то время как программы редко использовали гарантии CIS с реальными объектами типа объединения, гораздо чаще использовался тот факт, что указатели на объекты неизвестного происхождения должны были вести себя как указатели на членов объединения и иметь связанные с этим поведенческие гарантии.