Законное Использование offsetof Макроса в C / C++

Используйте werkzeug и заставьте своего демона включать основанный на HTTP сервер WSGI.

у Вашего демона есть набор маленьких приложений WSGI для отвечания информацией о статусе.

Ваш клиент просто использует urllib2, чтобы сделать POST или ПОЛУЧИТЬ запросы к localhost:somePort. Ваш клиент и сервер должен договориться о номере порта (и URL).

Это очень просто реализовать и очень масштабируемый. Добавление новых команд является тривиальным осуществлением.

Примечание, что Ваш демон не должен отвечать в HTML (это часто просто, хотя). Наши демоны отвечают на WSGI-запросы с JSON-закодированными объектами состояния.

8
задан Community 23 May 2017 в 10:32
поделиться

5 ответов

Что ж ... В C это очень полезно для любого места, где вам нужен код для описания структуры данных. Я использовал его, например, для создания сгенерированного во время выполнения GUI: s для установки параметров.

Это работало следующим образом: команда, которой требуются параметры, определяет локальную структуру, содержащую ее параметры, а затем описывает эту структуру для кода, который генерирует графический интерфейс, используя смещение , чтобы указать, где находятся поля. Использование смещений, а не абсолютных адресов позволяет коду графического интерфейса работать с любым экземпляром структуры, а не только с одним.

Это немного сложно быстро набросать в примере (я пробовал), но поскольку комментарии указывают на то, что пример в порядке , Я попробую еще раз.

Предположим, у нас есть автономный модуль, называемый «командой», который реализует какое-то действие в приложении. Эта команда имеет набор параметров, которые управляют ее общим поведением, которое должно быть показано пользователю через графический пользовательский интерфейс. Для целей этого примера предположим, что приложение является файловым менеджером, и команда может быть, например, «Копировать».

Идея состоит в том, что код копирования находится в одном файле C, а код графического интерфейса пользователя - в другом, а Код графического интерфейса пользователя не должен быть жестко запрограммирован для «поддержки» параметров команды копирования. Вместо этого мы определяем параметры в файле копирования, например так:

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. */

Затем команда копирования регистрирует свои параметры конфигурации в модуле графического интерфейса:

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 диалоговое окно, содержащее элементы управления, созданные во время выполнения, подходящие для редактирования этой команды. Параметры s:

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 знает только, где находится каждое значение life, выраженный как смещение, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого установили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.

Если бы мы также поддерживали динамические строки, нам потребовалась бы функция для копирования. Однако для данных конфигурации любую строку, вероятно, лучше всего выразить в виде массива статического размера char в структуре, что было бы хорошо.

Обратите внимание на тот факт, что модуль GUI знает только, где находится каждое значение life, выраженный как смещение, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого установили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.

Если бы мы также поддерживали динамические строки, нам потребовалась бы функция для копирования. Однако для данных конфигурации любую строку, вероятно, лучше всего выразить в виде массива статического размера char в структуре, что было бы хорошо.

Обратите внимание на тот факт, что модуль GUI знает только, где находится каждое значение life, выраженный как смещение, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого установили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.

Обратите внимание, как тот факт, что модуль GUI знает только, где находится каждое значение, выраженное в виде смещения, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого настроили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.

Обратите внимание, как тот факт, что модуль GUI знает только, где находится каждое значение, выраженное в виде смещения, позволяет нам предоставить функции диалога временную копию в стеке. Если бы мы вместо этого установили модуль GUI с прямыми указателями на каждое поле, это было бы невозможно, что было бы гораздо менее гибким.

4
ответ дан 5 December 2019 в 09:26
поделиться

Почему вы определяете свойства во время __ init __ ? Это запутанно и умно, так что вам лучше иметь действительно вескую причину. Проблема цикла, на которую указал Стеф, - лишь один из примеров того, почему этого следует избегать.

Если вам нужно заново определить, какие свойства имеет подкласс, вы можете просто выполнить del self. в метод подкласса __ init __ , или определить новые свойства в подклассе.

Также некоторые придирки стиля:

  • Отступ до 4 пробелов, а не 2
  • Не смешивайте типы кавычек без надобности
  • Используйте подчеркивание вместо верблюжьего регистра для имен методов. PropNames -> prop_names
  • PropNames не
6
ответ дан 5 December 2019 в 09:26
поделиться

По сути, все, что вы делаете с указателем на член ( T :: * ) в C ++, является хорошим кандидатом для использования offsetof в C. По этой причине , offsetof гораздо реже встречается в C ++.

Теперь это, конечно, немного зацикленный, поэтому вот несколько примеров:

  • Полуниверсальные функции сортировки для структур. qsort использует обратный вызов, что не идеально. Часто вам просто нужно отсортировать по естественному порядку одного члена, например третьего int в структуре. Гипотетический qsort_int может принимать для этой цели аргумент offsetof .
  • Точно так же можно написать макрос extract , чтобы вы могли сказать int out [10]; extract (int, & MyFoo [0], & MyFoo [10], out, offsetof (struct Foo, Bar));
2
ответ дан 5 December 2019 в 09:26
поделиться

Один из способов, которым я использовал его во встроенных системах, - это когда у меня есть структура, которая представляет структуру энергонезависимой памяти (например, EEPROM), но где я не хочу фактически создать экземпляр этой структуры в ОЗУ. Вы можете использовать различные уловки с макросами, которые позволят вам читать и записывать определенные поля из EEPROM, где offsetof выполняет работу по вычислению адреса поля в структуре.

Что касается «зла», вы должны помнить то, что множество вещей, которые традиционно делались в программировании на 'C', особенно на платформах с ограниченными ресурсами, теперь выглядит злым хакерством, если смотреть на него из роскошной среды современных вычислений.

5
ответ дан 5 December 2019 в 09:26
поделиться

offsetof относительно часто используется для программирования драйверов устройств, где обычно приходится писать на простом C, но иногда требуются некоторые «другие» функции. Предположим, у вас есть функция обратного вызова, которая получает указатель на некоторую структуру. Теперь эта структура сама по себе является членом другой более крупной «внешней» структуры. с "offsetof" у вас есть возможность изменять элементы "внешней" структуры, когда у вас есть доступ только к "внутреннему" члену.

Примерно так:

struct A
{
 int a1;
 int a2;
};

struct B
{
 int b1;
 int b2;
 A a;
};

void some_API_callback_func(A * a)
{
 //here you do offsetof 
 //to get access to B members
}

Конечно, это опасно, если у вас есть вероятность, что структура A используется не как часть структуры B. Но во многих местах, где структура для "some_API_callback_func" хорошо задокументирована, это прекрасно работает.

1
ответ дан 5 December 2019 в 09:26
поделиться