+10

Guidelines and tips for mixing up C structure and union.

I understood that struct and union are used to group data as a pack, with an exception that union stores its member values all in the same address in memory. I would like to know more about these data structures, so please share anything you know about them that I haven't mentioned. Differences, strengths and/or weaknesses, usage preferences etc. My first question is about mixing the two data structures, e.g. a struct inside a union, or a union inside a struct. Tell me when/why would/should we do that (mixing them up)? How (or in which situation) do we decide which should be inside the other, and what are the points to notice, the DOs and DON'Ts. Second question is about anonym struct or union and/or mix of the two. What/when/why the need to use these? what are the benefits (if any) over the use of named struct or union? Third question is, what difference between C and C++ union. I understand the difference between C and C++ struct, so it's okay 👌 Thanks in advance, 🙏

1/26/2020 5:50:54 PM

Ipang

11 Answers

New Answer

+9

I usually use a union for 2 things. - If I want to return 1 and only 1 type among a select few. - If I want to return 1 type and be able to manipulate it's internal bits with other types. In the first case, returning just a union would be a mistake, because there is no way to determine which type is active. For example if a function returned a union{ float, int } then how do you know if the active value is the float or the int? The solution is to nest a union inside a struct and use another identifier that you place inside the struct. For example struct{ bool identifier; union { float f; int i; }; }; The function would set the identifier to 0, if the active type is the float, or a 1 if the active value is the int. Of course I just use a bool because there are only 2 possibilities, you'd use a different type for the id if there were more. If I have to use a union, this is the one I go for.(before C++17) For example I use this in my math expression parser so that it can switch to floats if decimal points get involved while using integrals when not. - The 2nd case is actually much rarer, the only time I remember using it was when I was making my gameboy emulator. You see, the gameboy has 8 8 bit registers. However, the gameboy also has the ability to combine them together to form 4 16 bit registers. So the way you could go about it is to use a union like union Register { std::uint16_t u16; struct { std::uint8_t l; std::uint8_t h; }; }; This way you can easily access both versions without needing to use bit manipulation. ( although I did opt for just that later on though ) The problem with the struct inside the 2nd union is that it totally depends on the endianness of the machine, not to mention that anonymous structs are illegal C++ ( without an extension on the language ) but legal in C. (C11 I believe). Accessing non active types in C++ is also undefined behaviour, but not in C. In C++17 you should use std::variants instead. ( out of chars )

+8

Wow Ipang that is a mouthful where to begin outside of giving you the GeeksforGeeks reference as a starting point... https://www.geeksforgeeks.org/difference-structure-union-c/ I know that you do a lot of reading and always give good answers. Maybe we can set the stage from what GeeksforGeeks explains.

+8

I want to offer a different perspective on the difference between 'struct' and 'union', namely a set (naive type) theoretic distinction. One that might additionally assist the decision when to use what. In another response I want to draw parallels to structural concepts in OOP. Taking a naive standpoint we might consider a type being nothing but a set. A set of values that a variable of that type may assume. Let's start off with a specific type (set) S = {1, 2, 3}. From here, we can construct new types: Cartesian Product, SxS: The set of all ordered pairs (x, y) with x and y in S. Both x AND y must take on a value, neither may be empty. To be explicit, this type has the following values: SxS = { (1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (33) }; in total nine. This is the 'struct' with two members, each of type S: struct S_times_S { S x; S y; }; In C, requiring both members to have a definite value is a strictness requirement that applies on the usage level; the language (cannot) enforce that both members have a valid value. Union SuS: The set-theoretic union has of course only three elements, to be explicit: SuS = S. With some hand-waving, this is roughly the C union type. Roughly, because there is still a distinction between the members through their names. But this type can take on only three values: 1, 2 or 3. Disjoint union / "tagged" union, S+S: In case of the disjoint union, we make a distinction which set the value came from. It is related to the product type above, but with only one slot filled at a time. Let's call these for now the "left" side L and the "right" side R. Then the disjoint union has six elements: S+S = { L1, L2, L3, R1, R2, R3 }. In C we need an explicit tag to distinguish those two: struct { int tag; union { S x; S y }; }; The point being made here is that struct and union simply construct different types, in the sense that types are sets. So there is a logical distinction in what you want the types to express. (cnt'd...)

+8

What you can see from the above is the 'struct' expresses something like "BOTH", whereas 'union' expresses something like "EITHER". For an arbitrary but finite number of members, one could say that 'struct' expresses "ALL", 'union' expresses "ANY". I want to illustrate that with an example, offering a link between C and structural concepts in OOP. For that, consider books (as usual ^^). For simplicity, let a book be fully described by ALL of "author", "format", "pages" and, depending on the format, we require EITHER "file size" (for digital format) or "binding" and "weight" for printed books. The emphases are deliberate. In an OOP environment you would probably create a common superclass as follows: class AbstractBook { protected: string author; format_t format; unsigned pages; }; And derive concrete realisations as class PrintedBook : public AbstractBook { private: binding_t binding; unsigned weight; }; class DigitalBook : public AbstractBook { private: unsigned fileSize; }; What you have is a (disjoint) union of digital and printed books. It shouldn't surprise that, logically, a union appears in a C implementation, which could look like this: typedef enum { PRINT, DIGITAL } format_t; typedef enum { HARDCOVER, PAPERBACK } binding_t; struct book_s { const char* author; format_t format; unsigned pages; union { struct { binding_t binding; unsigned weight; }; unsigned file_size; }; }; int main() { struct book_s b = { .author = "Me", .format = DIGITAL, .pages = 506, .file_size = 128 }; struct book_s c = { .author = "Somebody Else", .format = PRINT, .pages = 122, .binding = HARDCOVER, .weight = 78 }; // ... return 0; } _____ This is only one aspect about 'struct' and 'union'. Others have already mentioned the common view points.

+7

A little bit of information here https://code.sololearn.com/ce4LYug0YIfN/?ref=app union are used when you limited memory resources. Low level system and kernel programming. Can be used for non-portable data type conversion (may not always work)

+7

In programs that communicate with each other over a network there could be different types of messages, e.g. with the first field indicating the message type. A union could be used for the message data structure in this case as the fields of the message could vary depending on the type of message. A given type of message could also have certain composite fields within it and in this case, you could use a struct (within the union) to represent the composite field.

+3

Thank you BroFar 🙏

+2

Thank you ~ swim ~ 🙏

+2

Thank you Coder Kitten 🙏

+1

Thank you Dennis 🙏

+1

Thank you Sonic 🙏