непересекающиеся объединения в C, Pascal и SML - PullRequest
0 голосов
/ 25 января 2019

Я изучал непересекающиеся союзы в программировании.Я сталкивался с высказыванием, что Pascal, SML и C имеют свои собственные версии объединения: variant record, construction и union.Также говорилось, что Pascal содержит «тег», который вам не нужно использовать, SML имеет тег, который требуется для его использования, а C не имеет тега.более того, SML выдаст исключение, если мы его неправильно использовали, Pascal разрешает проверку во время выполнения, а C не имеет функции проверки во время выполнения, и программист должен добавить поле для «тега» вручную.

Прежде всего, я не понимаю, что такое «тег».Я пытался взглянуть на некоторые примеры этих союзов, но не понял, что представляет собой «тег».Если «теги» важны, почему у C есть такой?В чем разница между этими союзами.Кроме того, я не нашел никаких материалов, связанных с «тегом» профсоюзов.Кроме того, что означает «проверка во время выполнения», что проверять?Было бы здорово увидеть примеры smiple, демонстрирующие эти функции.

Ответы [ 4 ]

0 голосов
/ 25 января 2019

В SML есть тег, который требуется для его использования [...] . кроме того, SML будет выдавать исключение, если мы использовали его неправильно,

Стандартный ML имеет алгебраических типов данных , которые содержат типов сумм и типов продуктов . типы сумм основываются на объединениях (и типы продуктов строятся на основе структур), но обрабатывают то, что вы называете тегированным или непересекающимся объединением, автоматически в компиляторе; вы указываете конструкторы , а скомпилированный код выясняет, как различать различные конструкторы с помощью сопоставления с шаблоном . Например,

datatype pokemon = Pikachu of int
                 | Bulbasaur of string
                 | Charmander of bool * char
                 | Squirtle of pokemon list

Таким образом, тип суммы может иметь разные конструкторы с разными параметрами, и сами параметры могут быть произведением других типов, включая типы сумм и включая сам определяемый тип, определяя тип данных рекурсивный. Это реализовано с помощью теговых объединений, но абстракции сверху обеспечивают больше синтаксического удобства.

Для пояснения, Standard ML не будет генерировать исключение, если оно используется неправильно, но выдает ошибку типа во время компиляции. Это из-за стандартной системы типов ML . Таким образом, вы не можете случайно иметь (void *) -поинтер, который вы приводите к чему-то, чего нет, что возможно в C.

0 голосов
/ 25 января 2019

Прежде всего, я не понимаю, что такое «тег».

В Википедии есть достаточно хорошее обсуждение общей концепции , которая начинается со списка синонимов, включая «теговое объединение».На самом деле, «теговый союз» является основным заголовком статьи, а непересекающийся союз является одним из синонимов.Он начинается с довольно краткого объяснения:

структура данных, используемая для хранения значения, которое может принимать несколько различных, но фиксированных типов.Только один из типов может использоваться одновременно, и поле tag явно указывает, какой из них используется.

Вы продолжаете спрашивать,

Если «теги» важны, почему у «С» есть один?

Насколько важны теги в этом контексте, это вопрос языкового дизайна, на котором написаны C, Pascal и SMLзанять разные позиции.Поскольку C склонен придерживаться довольно низкоуровневого подхода к большинству вещей и предоставить пользователям большой контроль, неудивительно, что он не заставляет использовать теги.Пользователи, которым нужны теги, могут сами сравнительно легко их реализовать, как я это делал иногда.

В качестве альтернативы было бы проще сказать, что C не имеет теговых союзов, каквообще встроенная языковая функция, только простые, без тегов союзы.С этой точки зрения, если вы хотите пометить объединение в C, вы должны реализовать его самостоятельно.Возможно, это наиболее последовательное мнение, но я понимаю, что оно отличается от того, которое представлено в материале, который вы изучали.

В чем разница между этими союзами.

Это разные реализации схожей концепции, предоставляемые разными языками.Полный анализ будет выходить за рамки разумного ответа SO.Как и многие вещи в области компьютерных наук и в других местах, абстрактная идея о несвязанных объединениях *1031* может быть реализована множеством различных способов.

Кроме того, я не нашел никакого материала, связанного сна «тег» союзов.

См. выше, и связанную статью Wikipedia.Я уверен, что вы также можете найти гораздо больше материала, особенно со списком синонимов WP для работы.

Далее, что означает «проверка во время выполнения», проверка чего?

Я должен был бы увидеть контекст и точное утверждение, чтобы быть уверенным, но, вероятно, ваш источник говорил о проверке одной или нескольких из следующих вещей:

  • , чтотег конкретного экземпляра объединения является одним из тех, которые определены для этого типа объединения, или
  • , что содержимое объединения имеет тип, указанный тегом, или
  • , чтоСписок альтернативных действий (см. ниже) охватывает все возможные альтернативы.

Было бы здорово увидеть примеры с примерами этих функций.

Мой Паскальслишком ржавый, чтобы быть полезным, и я не знаю 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, тег предоставляется вручную и явно, и язык не выделяет его специально.Кроме того, программист должен убедиться, что содержимое объединения имеет правильный тег.

Вы можете использовать такую ​​функцию с такой функцией, которая опирается на тег, чтобы определить, как обрабатывать экземплярыТип соединения:

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;
    }
}
0 голосов
/ 25 января 2019

Такие непересекающиеся союзы можно назвать очень ранней формой полиморфизма.У вас есть один тип, который может иметь несколько форм.В некоторых языках, какая из этих форм используется (активна), различается членом типа, называемого тегом.Это может быть логическое значение, байт, перечисление или какой-либо другой порядковый номер.

В некоторых (более старых?) Версиях Pascal тег действительно должен содержать правильное значение.«Объединение» Паскаля (или, как их называют в Паскале, вариант записи ) содержит значение, которое определяет, какая из ветвей в данный момент «активна».

Пример:

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;

В таких версиях Pascal, если Tag имеет значение 0, вы можете получить доступ только к B0, B1, B2 или B3, но не к другим вариантам.Если Tag равен 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 };
    };
}
0 голосов
/ 25 января 2019

Тег - это все, что говорит вам, какой член союза используется в настоящее время.Обычно это enum, но может быть целым числом, логическим значением или битовым полем, основанным на одном из них.

Пример:

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, не заставляющий вас использовать встроенный тегу вас есть больше контроля над макетом и размером ваших данных.Например, вы можете использовать тег битового поля и размещать его рядом с другой информацией битового поля, хранящейся в вашей структуре, так что битовые поля объединяются, что дает вам экономию пространства;или иногда член объединения, используемый в данный момент, неявно зависит от контекста, в котором находится ваш код, и в этом случае тег вообще не нужен.

...