Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a safe tagged union in C

Tags:

c

unions

Let's suppose you are writing a C struct which represents a course in a meal. One of the fields in the course struct is of type:

enum TP_course {STARTER, MAINCOURSE, DESSERT};

Then, depending on the type of the course, you have a subtype:

enum TP_starter {SALAD, GRILLEDVEGETABLES, PASTA};
enum TP_maincourse {BEEF, LAMB, FISH};
enum TP_dessert {APPLEPIE, ICECREAM, MOUSSE};

Given that only one of such enums will be used at a time (depending on the type of the course), it makes sense to aggregate them in a union:

union U_subtype {
   enum TP_starter s;
   enum TP_maincourse m;
   enum TP_dessert d;
};

So the course struct would look like this:

struct S_course {
   enum TP_course type;
   union U_subtype stype;
   float price_in_USD;
   int availability;
   ...and all the rest of data would follow...
};

Ok, everything is clear, but... is there any coding strategy I could follow to try to enforce safe access to the stype tagged union above? Perhaps making it opaque in some way?

For example, if I write a switch/case block for an enum and I forget to write a case for a value, the compiler will trigger a warning, which is of great help for maintaining the code in the future. But if I access stype.s without first checking if type==STARTER, the compiler cannot be smart enough for realizing of the risky coding, and won't warn at all.

Can I organize the code in some way so that it's not possible to access the members of the U_subtype union except in a very limited place where I clearly document how the access to such members must be done?

like image 809
cesss Avatar asked Mar 16 '17 20:03

cesss


People also ask

What is tagged union in C?

A tagged union declaration looks just like a C union, except that it you must specify the @tagged qualifier when declaring it. For example: @tagged union Foo { int i; double d; char *@fat s; }; The primary difference with C unions is that a tagged union includes a hidden tag.

What is union in C with example?

We use the union keyword to define unions. Here's an example: union car { char name[50]; int price; }; The above code defines a derived type union car .

What is tagged union in SV?

A tagged union is a type-checked union. That means you can no longer write to the union using one member type, and read it back using another. Tagged union enforces type checking by inserting additional bits into the union to store how the union was initially accessed.

What type checking which union contains a tag?

Type constructors produce a tagged union type, given the initial tag type and the corresponding type. Mathematically, tagged unions correspond to disjoint or discriminated unions, usually written using +. Given an element of a disjoint union A + B, it is possible to determine whether it came from A or B.


1 Answers

You can

  1. Hide the whole struct and expose accessor functions that act on a pointer

.

/* header */
struct S_course; //forward declaration
enum TP_starter {SALAD, GRILLEDVEGETABLES, PASTA};
enum TP_maincourse {BEEF, LAMB, FISH};
enum TP_dessert {APPLEPIE, ICECREAM, MOUSSE};
void S_course__set_starter(struct S_course *this,  enum TP_starter starter);

//accessor functions
void S_course__set_maincourse(struct S_course *this,  enum TP_maincourse maincourse);
void S_course__set_dessert(struct S_course *this,  enum TP_dessert dessert);


/* c file */
enum TP_course {STARTER, MAINCOURSE, DESSERT};
union U_subtype {
   enum TP_starter s;
   enum TP_maincourse m;
   enum TP_dessert d;
};
struct S_course {
   enum TP_course type;
   union U_subtype stype;
   float price_in_USD;
   int availability;
   /*...*/
};
void S_course__set_starter(struct S_course *this,  enum TP_starter starter)
{
    this->type = STARTER;
    this->stype.s = starter;
}
  1. Use member names that scream don't touch me, or a name like tagged_union, which should make it obvious how it needs to be accessed.

    or

  2. Switch to C++ and use its access control features (private/protected) to hide only some members while allowing access through public member/friend functions

like image 139
PSkocik Avatar answered Nov 14 '22 22:11

PSkocik