Well ... In C, it's very useful for any place where you need code to describe a data structure. I've used it e.g. to do run-time-generated GUI:s for setting options.
This worked like this: a command that needs options defines a local structure holding its options, and then describes that structure to the code that generates the GUI, using offsetof
to indicate where fields are. Using offsets rather than absolute addresses allows the GUI code to work with any instance of the struct, not just one.
This is bit hard to sketch quickly in an example (I tried), but since comments indicate an example is in order, I'll try again.
Assume we have a self-contained module, called a "command", that implements some action in the application. This command has a bunch of options that control its general behaviour, which should be exposed to the user through a graphical user interface. For the purposes of this example, assume the application is a file manager, and the command could be e.g. "Copy".
The idea is that the copy code lives in one C file, and the GUI code in another, and the GUI code does not need to be hard-coded to "support" the copy command's options. Instead, we define the options in the copy file, like so:
struct copy_options
{
unsigned int buffer_size; /* Number of bytes to read/write at a time. */
unsigned int copy_attributes; /* Attempt to copy attributes. */
/* more, omitted */
};
static struct copy_options options; /* Actual instance holding current values. */
Then, the copy command registers its configuration settings with the GUI module:
void copy_register_options(GUIModule *gui)
{
gui_command_begin(gui, "Copy");
gui_command_add_unsigned_int(gui, "Buffer size", offsetof(struct copy_options, buffer_size));
gui_command_add_boolean(gui, "Copy attributes", offsetof(struct copy_options, copy_attributes));
gui_command_end(gui);
}
Then, let's say the user asks to set the copy command's options. We can then first copy the current options, to support cancelling, and ask the GUI module for a dialog holding controls, built at run-time, suitable for editing this command's options:
void copy_configure(GUIModule *gui)
{
struct copy_options edit = options;
/* Assume this opens a modal dialog, showing proper controls for editing the
* named command's options, at the address provided. The function returns 1
* if the user clicked "OK", 0 if the operation was cancelled.
*/
if(gui_config_dialog(gui, "Copy", &edit))
{
/* GUI module changed values in here, make edit results new current. */
options = edit;
}
}
Of course, this code assumes the settings to be pure value-types, so we can copy the struct using simple struct assignment. If we also supported dynamic strings, we'd need a function to do the copying. For configuration data though, any string would probably best be expressed as a statically-sized char
array in the struct, which would be fine.
Note how the fact that the GUI module only knows where each value lives expressed as an offset allows us to provide the dialog function with a temporary on-stack copy. Had we instead set up the GUI module with direct pointers to each field, this would not be possible which would be far less flexible.