>>если значения нашего enum'а взяты из /etc/services
> ЩИТО? в /etc/services нет перечислений, там только номера портов Да, там только перечисление номеров портов с именами сервисов и комментами. Вещь которую напрашивается оттранслировать в массив, но как ссылаться на элементы? Можно указателями, но если у нас есть основания полагать, что мы ещё и по имени захотим ссылаться туда?
>>Ты уверен, что вся информация связанная с константой обязательно влезет в машинное слово, в том числе и каноническое имя для этой константы, и ещё описание для пользователя, если он захочет больше подробностей? С переводами на пару десятков языков.
> Вы вообще о чём? Мы говорим о перечислениях и о конкретной оптимизации
> и о том, почему лучше уволить разраба, к коду которого она
> применима. Если вам надо таскать всю указанную информацию, то перечислением и
> той конкретной оптимизацией тут и не пахнет.
Мозг включи, пожалуйста. Как раз именно перечислением здесь и пахнет. Это ты пытаешься всю информацию запихать в непосредственное значение, которое будет #[derive(Copy,Clone)]. Мне эта идея может показаться удачной только тогда, когда я стопудов уверен, что всё что надо влезет, и что потом мне не потребуется затем пихать туда больше информации, и что это не кончится тем, что структура вылезет за пределы 128 бит, и вопрос о том, что структура тут лишняя, встанет ребром. И перечисление спеллов -- это явно вещь, которая очень быстро распухнет так, что она не влезет ни в 128 бит, ни в 256, если туда пихать информацию о том, offensive оно или defensive; может быть использовано к механической цели, или только к белковой; называется на букву 'а' или на какую-другую; и тп.
Тебе какой пример больше нравится? С авадой кедаврой или с /etc/services?
Давай я на втором, он тебе более непонятен оказался почему-то. Как с /etc/services работать из C?
Есть разные варианты (скажем поискать существующие API -- один из самых перспективных), но я предлагаю следующий:
1. пишем скрипт, который из /etc/services делает ./services-generated.h с содержанием типа:
enum Service {
TCPMUX = 1,
COMPRESSNET = 2,
RJE = 5,
...
}
static struct ServiceDescription {
char *name;
char *description;
} _descriptions[] = {
[TCPMUX] = { .name = "tcpmux", .description = "TCP port service multiplexer" },
[COMPRESSNET] = { ...
...
};
_descriptions было бы круто спрятать из .h файла куда-нибудь, но тогда не удастся следующие функции заинлайнить статически (это дурацкие ограничения C, их может быть можно обойти инлайном в линк-тайме, но я не знаю об этом ничего -- слышал звон, да не знаю где он).
2. пишем services.h:
#include "./services-generated.h"
static inline int service_port(enum Service s) {
return (int)s; // в нашем случае маппинг тривиален, но это не обязательно
}
static inline char *service_name(enum Service s) {
return _descriptions[s].name
}
static inline char *service_description(enum Service s) {
return _descriptions[s].description
}
Помимо этого у нас могут быть функции типа:
// NB: will return NULL if decoder is unimplemented
static inline struct PacketDecoder *service_decoder(enum Service s) {
// ...
}
static inline bool service_encrypted(enum Service s) {
// ...
}
Что ещё у нас может быть мне лень придумывать, потому что я не знаю, что это за программа такая и какие функции она выполняет. Но я думаю этого достаточно. Какие-то из этих функций могут использовать индексацию массива, если этот массив создаётся одним и тем же "поставщиком" что и сам enum (в нашем случае это скрипт), то есть если способ создания массива даёт гарантию соответствия индексов записям в массиве. Другие функции просто неразумно делать таким образом, потому что они могут обрабатывать небольшое количество значений enum'а -- скажем service_decoder может возвращать декодеры для десятка протоколов, и такой декодер может иметь пяток-десяток указателей на функции внутри с сопутствующей информацией, то есть занимать десятки байт, но выделять память под сотни структур таблички там, где будет достаточно десятка... ну это не самый удачный подход. Там можно повыкобениваться с табличкой указателей на структуры (всего по восемь байт на каждый указатель там, в том числе и NULL), но это уже декларативные глупости: для таких целей switch понятнее и, можно надеятся, короче в смысле количества байт в бинаре, требуемых на реализацию.
Третьи функции, которые вовсе не в нашей библиотеке объявлены, а в другом приложении, которое нашей библиотекой пользуются, вообще не могут полагаться на значения enum'а. Они даже не могут полагаться на то, что значением HTTP будет 80, а не что-то ещё, если конечно мы не гарантируем это в документации, потому что это внутренняя деталь реализации, которая может измениться завтра, когда нам в голову придёт другая какая-нибудь идея. Например, чтобы значение enum'а вычислялось бы по формуле: ip_port * 2 + (tcp ? 0 : 1). В смысле если это tcp порт, то номер сервиса -- это удвоенный порт, а если udp, то удвоенный и увеличенный на 1. Или не, ещё круче будет использовать бит знака для этого, чтобы tcp сервисы были бы положительными, а udp отрицательными.