Я изучал непересекающиеся союзы в программировании. Я столкнулся с высказыванием, что Pascal
, SML
и C
имеют свою версию объединения: variant record
, construction
и union
. Также было сказано, что Pascal
содержит «тег», который вам не нужно использовать, SML
имеет тег, который вам требуется для его использования, а C
не имеет тега. кроме того, SML
выдаст исключение, если мы использовали его неправильно, Pascal
разрешает проверку во время выполнения, а C
не имеет функции проверки во время выполнения, и программист должен вручную добавить поле для «тега».
Во-первых, я не понимаю, что такое "тег". Я пытался посмотреть на некоторые примеры этих союзов, но не понял, что представляет собой «тег». Если «теги» важны, то почему они есть у C
? чем отличаются эти союзы.
Также я не нашел материала, связанного с "меткой" союзов.
Кроме того, что означает «проверка во время выполнения», проверка чего? Было бы здорово увидеть простые примеры, демонстрирующие эти функции.
Тег — это все, что говорит вам, какой член объединения используется в данный момент. Обычно это перечисление, но может быть целым числом, логическим значением или битовым полем на основе одного из них.
Пример:
union my_union { char *string; void *void_ptr; long integer; };
struct my_tagged_union {
union my_union the_union;
enum { is_string, is_void_ptr, is_integer } the_tag;
};
C не заставляя вас использовать встроенный тег, означает, что у вас больше контроля над макетом и размером ваших данных. Например, вы можете использовать тег битового поля и поместить его рядом с другой информацией о битовом поле, которую вы храните в своей структуре, чтобы битовые поля были объединены, что дает вам экономию места; или иногда член объединения, который в настоящее время используется, является неявным из контекста, в котором находится ваш код, и в этом случае тег вообще не нужен.
First of all, I don't understand what is "tag".
В Википедии есть достаточно приятное обсуждение общей концепции, который начинается со списка синонимов, включая «союз с тегами». Собственно, «меченый союз» — это основной заголовок статьи, а непересекающийся союз — один из синонимов. Он начинается с довольно краткого объяснения:
a data structure used to hold a value that could take on several different, but fixed, types. Only one of the types can be in use at any one time, and a tag field explicitly indicates which one is in use.
Вы продолжаете спрашивать,
If "tags" are important, how come C does have one?
Насколько важны теги в этом контексте — это вопрос дизайна языка, по которому C, Pascal и SML занимают разные позиции. Поскольку язык C склонен применять довольно низкоуровневый подход к большинству вещей и предоставлять пользователям большой контроль, неудивительно, что он не требует использования тегов. Пользователи, которым нужны теги, могут сравнительно легко реализовать их сами, что я и сам иногда делал.
В качестве альтернативы, может быть проще сказать, что C не имеет пометил объединения как встроенную функцию языка вообще, только простые, непомеченные объединения. С этой точки зрения, если вы хотите помеченное объединение в C, вам нужно реализовать его самостоятельно. Это, вероятно, наиболее последовательная точка зрения, но я полагаю, что она отличается от представленной в материале, который вы изучали.
what is the difference between those unions.
Это разные реализации одной и той же концепции, предоставляемые разными языками. Полный анализ выходит за рамки разумного объема ответа SO. Как и многое другое в компьютерных науках и других областях, абстрактная идея непересекающихся объединений можно реализовать множеством различных способов.
Also, I didn't find any material related to the "tag" of unions.
См. выше и связанную статью в Википедии. Я уверен, что вы могли бы найти гораздо больше материала, особенно со списком синонимов WP для работы.
Futhermore, what does it mean "checking during runtime", checking what?
Чтобы быть уверенным, мне нужно увидеть контекст и точное утверждение, но вполне вероятно, что ваш источник говорил о проверке одной или нескольких из следующих вещей:
It will be great to see smiple examples that show those features.
Мой Паскаль слишком ржавый, и я не знаю SML. Однако даже простой пример на C может быть поучительным:
enum my_tag { INT_TAG, STRING_TAG, DOUBLE_TAG };
union disjoint_union {
struct {
enum my_tag tag;
int an_int;
};
struct {
enum my_tag tag_s;
char *a_string;
};
struct {
enum my_tag tag_d;
double a_double;
};
};
union disjoint_union u = { .tag = INT_TAG, .an_int = 42 };
union disjoint_union u2 = { .tag = STRING_TAG, .a_string = "hello" };
union disjoint_union u3 = { .tag = DOUBLE_TAG, .a_double = 3.14159 };
Поскольку это C, тег предоставляется вручную и явно, и язык специально не различает его. Кроме того, программист должен убедиться, что содержимое объединения имеет правильный тег.
Вы можете использовать такую вещь с такой функцией, которая полагается на тег, чтобы определить, как обрабатывать экземпляры типа union:
void print_union(union disjoint_union du) {
switch (du.tag) {
case INT_TAG:
printf("%d", du.an_int);
break;
case STRING_TAG:
printf("%s", du.a_string);
break;
case DOUBLE_TAG:
printf("%f", du.a_double);
break;
}
}
Такие непересекающиеся объединения можно было бы назвать очень ранней формой полиморфизма. У вас есть один тип, который может иметь несколько форм. В некоторых языках, какая из этих форм используется (активна), определяется членом типа, называемым тегом. Это может быть логическое значение, байт, перечисление или какой-либо другой порядковый номер.
В некоторых (старых?) версиях Паскаля тег фактически должен содержать правильное значение. «Объединение» Паскаля (или, как они называются в Паскале, вариант записи) содержит значение, которое отличает, какая из ветвей в данный момент «активна».
Пример:
type
MyUnion = record // Pascal's version of a struct -- or union
case Tag: Byte of // This doesn't have to be called Tag, it can have any name
0: (B0, B1, B2, B3: Byte); // only one of these branches is present
1: (W0, W1: Word); // they overlap each other in memory
2: (L: Longint);
end;
В таких версиях Паскаля, если Тег имеет значение 0, вы можете получить доступ только к B0, B1, B2 или B3, но не к другим вариантам. Если тег равен 1, вы можете получить доступ только к W0 и W1 и т. д.
В большинстве версий Pascal такого ограничения нет, и значение тега является чисто информативным. Во многих из них вам даже не нужно явное значение тега:
MyUnion = record
case Byte of // no tag, just a type, to keep the syntax similar
etc...
Обратите внимание, что записи вариантов Pascal не являются чистыми объединениями, где каждая часть является альтернативой:
type
MyVariantRec = record
First: Integer; // the non-variant part begins here
Second: Double;
case Byte of // only the following part is a "union", the variant part.
0: ( B0, B1, B2, B3: Byte; );
1: ( W0, W1: Word; );
2: ( L: Longint);
end;
В C вам нужно было бы вложить объединение в структуру, чтобы получить что-то почти такое же:
// The following is more or less the equivalent of the Pascal record above
struct MyVariantRec
{
int first;
double second;
union
{
struct { unsigned char b0, b1, b2, b3; };
struct { unsigned short w0, w1 };
struct { long l };
};
}
SML has a tag that you required to use it [...]. furthermore, SML will throw exception if we used it wrong,
Стандартный ML имеет алгебраические типы данных, которые содержат типы суммы и типы продуктов. типы суммы строится поверх объединений (а типы продуктов строится поверх структур), но автоматически обрабатывает то, что вы называете тегированным или непересекающимся объединением в компиляторе; вы указываете конструкторы, и скомпилированный код выясняет, как различать разные конструкторы через сопоставление с образцом. Например,
datatype pokemon = Pikachu of int
| Bulbasaur of string
| Charmander of bool * char
| Squirtle of pokemon list
Таким образом, тип суммы может иметь разные конструкторы с разными параметрами, а сами параметры могут быть произведением других типов, включая типы сумм и включая сам определяемый тип, что делает определение типа данных рекурсивным. Это реализовано с помощью объединений с тегами, но абстракции сверху обеспечивают большее синтаксическое удобство.
Чтобы уточнить, стандартный ML не выдает исключение при неправильном использовании, а выдает ошибка типа во время компиляции. Это из-за Стандартная система типов ML. Таким образом, вы не можете случайно получить (void *)
-указатель, который вы приводите к чему-то, чем он не является, что возможно в C.
Вероятно, речь идет о ведении записей, чтобы сообщить, какой тип члена хранит объединение.