#c #c #struct
Вопрос:
Есть несколько проектов на языке Си со структурами, полными ifdef (например. Вольфссл https://github.com/wolfSSL/wolfssl/blob/bb70fee1ecff8945af8179f48e90d78ea7007c66/wolfssl/internal.h#L2792)
struct {
int filed_1;
int field_2;
#ifdef SETTING_A
int filed_b;
#endif
#ifdef SETTING_B
int field_b;
#endif
}
Причина в том, чтобы уменьшить размер структуры для неиспользуемых опций.
Есть много ifdef! Повсюду!
Существует ли способ C избавиться от этих ifdef, сохранив возможность компилятора оптимизировать неиспользуемые поля? Может быть, с шаблонами, использованием или наследованием CRTP?
Комментарии:
1. Вы смотрите на проект C. В C не так много возможно в этом отношении. В C вы можете просто использовать (множественное) наследование.
2. С наследование использует таблицу виртуальных указателей и, таким образом, влияет на производительность. Также этот подход требует наличия 4 разных классов для 2 настроек. Что делать, если у меня 10 настроек?
3. наследование не подразумевает наличие таблицы v
4. Даже если бы вы смогли это сделать, всем пользователям кода все равно необходимо выполнить проверку во время компиляции, существуют ли field_a и field_b.
5. @XeenychXeenych Структура без виртуальных участников не имеет виртуальных накладных расходов
Ответ №1:
Вы можете сделать это на C 20 с [[no_unique_address]]
помощью и некоторой хитрости. Однако это не гарантирует результат для небольших типов, поэтому я все равно предлагаю вам использовать #define
s
template<typename>
struct Empty {};
template<typename T, bool enable, typename uniquer>
using MaybeEmpty = std::conditional_t<enable, T, Empty<uniquer>>;
struct foo {
int filed_1;
int field_2;
[[no_unique_address]] MaybeEmpty<int, settingA, struct filed_b_uniquer> filed_b;
[[no_unique_address]] MaybeEmpty<int, settingB, struct field_b_uniquer> field_b;
};
До C 20 это должно было быть сделано с базовыми классами
struct with_filed_b {
int filed_b;
};
struct with_field_b {
int field_b;
};
struct foo : MaybeEmpty<with_filed_b, settingA, struct filed_b_uniquer>, MaybeEmpty<with_field_b , settingB, struct field_b_uniquer> {
int filed_1;
int field_2;
};
Комментарии:
1. Выглядит неплохо. Как насчет более старого C ?
2. @XeenychXeenych до этого единственным способом, чтобы пустые объекты не занимали места, было то, что они были базовыми подобъектами
3. Не могли бы вы привести пример, пожалуйста?
4. @GuillaumeRacicot упс, исправлено