Improved readability with anonymous unions in C

Lets imagine you're defining a structure Img to manipulate images. Among the properties of Img there will be the dimensions of the image. This is very probably an array of two integers, something like: int dims[2]. Then comes the question, is this dims = {width, height} or dims = {height, width} ? If you don't mind, you'll use numerical indices, 0 and 1, and will, yes you will, mix them up one day or the other. So, to prevent that, you can define a macro or enumeration like #define width 0 and #define height 1, promise yourself to always use them, and pollute the name space happily. Else, you could avoid using one single array and use two properties instead: int width; and int height;. Much safer, but if you want to pass the two dimensions at once you can't anymore, that's going to make interface of functions heavier. So you may think of defining another structure struct Dimension {int width; int height;}; and use it as: struct Img {struct Dimension dims;} theImg;. Now you can access each dimension explicitly or pass them both at once when necessary. Using a struct hides the fact that the dimension are still a block of two integers in memory. Of course you can still express it by casting: (int*)&(theImg.dims) which is a bit lengthy isn't it?

Thanks to anonymous unions you can go one step further and improve on readability, by writing Img as follow:

Thanks to automatic promotion of dims, width and height at the struct Img scope thanks to the anonymous union and struct, they can be accessed directly as theImg.dims, theImg.width and theImg.height while being the same data in memory. One can manipulate them as int* or two int as necessary. If you wish to manipulate as the union, the preprocessor will help you solve a little problem: for the redirection to works the union must be declared inside Img. You can't write:

and use Dimension later. You could write the union declaration twice:

Awful code duplication, you're guaranted to forget to update one of the declarations the day it will change. Using the preprocessor instead avoid any trouble:

No cast, as short as you can get, available as union, int* and two int. Bingo!

Finally, a complete example to test:

Edit on 2022/11/28: Note that you have to take care of eventual padding in the inner struct of the union ! If needed protect it with __attribute__((packed)).

2021-10-06
in All, C programming,
134 views
Copyright 2021-2024 Baillehache Pascal