Ну ... В C это очень полезно для любого места, где вам нужен код для описания структуры данных. Я использовал это, например. сделать сгенерированный во время выполнения графический интерфейс: s для настройки параметров.
Это работает следующим образом: команда, которой нужны параметры, определяет локальную структуру, содержащую ее параметры, а затем описывает эту структуру в коде, который генерирует графический интерфейс, используя offsetof
, чтобы указать, где находятся поля. Использование смещений, а не абсолютных адресов, позволяет коду GUI работать с любым экземпляром структуры, а не только с одним.
В примере немного сложно быстро набросать (я пытался), но, поскольку комментарии указывают, что пример в порядке, я попробую еще раз.
Предположим, у нас есть автономный модуль, называемый «командой», который реализует некоторое действие в приложении. Эта команда имеет несколько параметров, которые управляют ее общим поведением, которые должны быть доступны пользователю через графический интерфейс пользователя. Для целей этого примера предположим, что приложение является файловым менеджером, и команда может быть, например, "Копировать".
Идея состоит в том, что код копии находится в одном файле C, а код GUI - в другом, и код GUI не нужно жестко кодировать для «поддержки» параметров команды копирования. Вместо этого мы определяем параметры в файле копирования, например:
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. */
Затем команда copy регистрирует свои параметры конфигурации с помощью модуля GUI:
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);
}
Тогда, скажем, пользователь просит установить параметры команды копирования. Затем мы можем сначала скопировать текущие параметры для поддержки отмены и запросить в модуле GUI диалоговое окно, содержащее элементы управления, созданные во время выполнения, подходящие для редактирования параметров этой команды:
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;
}
}
Конечно, этот код предполагает, что настройки являются чисто типами значений, поэтому мы можем скопировать структуру, используя простое присвоение структуры. Если бы мы также поддерживали динамические строки, нам понадобилась бы функция для копирования. Для данных конфигурации, однако, любая строка, вероятно, лучше всего будет выражаться в виде массива char
статического размера в структуре, что будет хорошо.
Обратите внимание, что тот факт, что модуль GUI знает только, где находится каждое значение, выраженное в виде смещения, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого настроили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.