Nixon 3 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Для доступа по индексу можно так сделать enum VARIABLES { VAR1, VAR2, ... VARN, VAR_MAX }; описание списка переменных const TVAR VarArray[VAR_MAX] = { [VAR1] = <тут ваша реализация>, [VAR2] = <тут ваша реализация>, ... [VARN] = <тут ваша реализация> }; собственно ваш реестр инициализации. Обращение к реестру можно делать по индексу (0-N) или по имени (VAR1-VARN). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Для доступа по индексу можно так сделать... :a14: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Вот чтобы не плодить тем, возник вопрос. Есть структура в вижуал студио. Ее поля имеют тип enum. Эта структура необходима для сериализации по юарту. Заниматься разборкой каждого поля, или, особо извращённым способом, делать каждое поле методом, пишущим себя в выходной поток нет ни желания, ни необходимости. Поэтому аккуратно подставив pragma pack попробовал. Все замечательно, но вот студия считает, что поля типа моего enum имеют тип int, обьявление у меня простое, по шариковски, typedef emum {Eins ,Zwei, Polizei} eMytype; А вот GCC решил, что такой тип прекрасно ложится в чар, на что имеет право Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using enum-base; if not explicitly specified, the underlying type of a scoped enumeration type is int. In these cases, the underlying type is said to be fixed. Following the closing brace of an num-specifier, each enumerator has the type of its enumeration. (хотя мой инглиш слаб, и может и не имеет). Теперь мысли что делать. В с++ с типами строже, отказываться от типа энум не хочу, там это ошибка, причем полезная. Можно сделать как typedef emum {Eins ,Zwei, Polizei, empty = 0xffffff}, в Гцц, тогда он сделает энумы интом, но это тоже так себе идея, тем более скорее хотелось бы пыл студии усмирить на предмет делать все это интом. Третий вариант в студии enum class eMytype : char {Eins ,Zwei, Polizei} сделать, но тогда не совсем понял как юзать старый трюк в С с " {Eins ,Zwei, Polize, max_enum_elents}, max_enum_elents будет строго типизировано и пробежаться по его его варинтам вплоть до него "по индексу" не выйдет. Для доступа по индексу можно так сделать enum VARIABLES { VAR1, VAR2, ... VARN, VAR_MAX }; описание списка переменных const TVAR VarArray[VAR_MAX] = { [VAR1] = <тут ваша реализация>, [VAR2] = <тут ваша реализация>, ... [VARN] = <тут ваша реализация> }; собственно ваш реестр инициализации. Обращение к реестру можно делать по индексу (0-N) или по имени (VAR1-VARN). Симпатично, жаль это since C99, поэтому не так много где описано и использовано. Буду знать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба ... Пытаясь понять этот трудночитаемый набор слов, мне удалось понять мысль - один компилятор трактует enum как char, а другой - как int. Но это вроде как решаемо: всего лишь в enum нужно явно указать тип хранимых данных. Примерно так: typedef enum { Eins, Zwei, Polizei, empty = (uint32_t)0xffffff } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба А наоборот как ? typedef enum {t1, t2, t3 = (char) 100} myE; #pragma pack (1) struct My { myE e1; myE e2; myE e3; }; #pragma pack () int main() { cout << offsetof(My, e1) << endl; cout << offsetof(My, e2) << endl; } ...... e1 e2 e3 как были int так и остались. Компилятору по барабану все эти (char), он, как я понимаю, обязан уложиться в int и не более. Попросить его ограничиться char не могу, это compilator depended Можно было бы как enum class myE : char {t1, t2, t3, eMAX}; #pragma pack (1) struct My { myE e1; myE e2; myE e3; } my; #pragma pack () int main() { for (myE i = myE::t1; i < myE::eMAX; i++) Только вот так не получится , да и понятно почему (второе изображение) Выходит в С слишком опасно, в С++ слишком неудобно либо неэффективно. Решение есть, вот оно и ищется Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба По-ходу я ошибся с явным указанием типа enum, у меня не работает :( Нужно это делать ключами компилятора: http://www.keil.com/support/man/docs/armcl...11640303038.htm Кстати, у меня pragma pack вот так используется: #pragma pack(push, 1) .... #pragma pack(pop) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба max_enum_elents будет строго типизировано и пробежаться по его его варинтам вплоть до него "по индексу" не выйдет.Явное приведение типа все еще работает. for(uint_fast8_t i = 0;i < uint_fast8_t(eMytype::max_enum_elents); ++i)/ Симпатично, жаль это since C9918 лет, уже не девочка... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Явное приведение типа все еще работает. for(uint_fast8_t i = 0;i < uint_fast8_t(eMytype::max_enum_elents); ++i)/ 18 лет, уже не девочка... да оно и неявно сработает, и в этом случае без enum class "eMytype::max_enum_elents" будет лишним, но нехорошо. Ладно, пусть нехорошо, pragma pack тоже совсем нехорошо. Но как enum сделать гарантированно char ами? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Но как enum сделать гарантированно char ами? Остается только ключами компилятора Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба По-ходу я ошибся с явным указанием типа enum, у меня не работает :( Нужно это делать ключами компилятора: http://www.keil.com/support/man/docs/armcl...11640303038.htm Кстати, у меня pragma pack вот так используется: #pragma pack(push, 1) .... #pragma pack(pop) я думал, что могут быть такие ключи, но это еще меньше делать хочется. Если я делаю такие мерзости как явное приведение типов, то стараюсь писать static_cast <>, такая многословность в таких случаях в тему, при просмотре кода понимаю, что писав это понимал что делаю и чем чревато. А вот ключ компилятора ( если он есть) будем забыт сразу, в коде не видно. Признаюсь, особенно не мучался ранее стандартами, в голове засело, что enum это int, то ли книги так пишут, что непонятно. На самом деле enum это может и char и short и int быть, и , насколько помню, при сравнении такого enum с другим типом, имеющим неявное преобразование не будет даже warning.. А вот тут споткнулся Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба А вот тут споткнулся В "протокольных" делах enum не использую, но очень активно использую union: static const struct { // Device answers uint8_t Ok; uint8_t Unknown; uint8_t WrongFirmware; uint8_t WriteError; // Common commands uint8_t GetDeviceInfo; uint8_t DeviceReset; uint8_t BootloaderActivate; // Bootloader commands uint8_t GetFirmwareFitures; uint8_t ChunkUpload; uint8_t PageWrite; uint8_t FirmwareVersionUpdate; // Secret commands ..... } Command = { 0x00, 0x01, 0x02, 0x03, // Device answers 0xA0, 0xA1, 0xA2, // Common commands 0xE0, 0xE1, 0xE2, 0xE3, // Bootloader commands ...... // Secret commands }; ..... #if defined ( __CC_ARM ) // Arm Compiler v5 #pragma anon_unions #endif #pragma pack(push, 1) struct DeviceInfo { Settings::Version bootloaderVersion; Settings::Version firmwareVersion; Settings::Version hardwareVersion; Settings::SerialNumber serialNumber; ....... }; struct FirmwareFitures { uint32_t baseAddr; // Firmware Base Address uint32_t memorySize; // Flash memory size (including Bootloader and Firmware regions both) uint8_t chunkSize; uint16_t pageSize; }; struct FirmwareCheckZone { uint16_t crc16; uint16_t sizeKb; }; ...... struct Report // 64 bytes { uint8_t command; union { uint8_t payLoad[REPORT_SIZE_BYTES - sizeof(command)]; struct DeviceInfo deviceInfo; struct FirmwareFitures firmwareFitures; struct { uint32_t addr; uint8_t data[FIRMWARE_CHUNK_SIZE_BYTES]; } chunk; struct { uint32_t addr; } page; ............... }; }; #pragma pack(pop) Оба кода одинаково работают на Qt5 и под keil (v5 и v6), что очень удобно. Доп. ключей компиляции не использую. Использование const struct вместо define и enum (ну, не люблю их) позволяет мне делать код более читаемым. Разбор пакетов, в которых идут разношерстные данные благодаря union делает его очень компактным и также хорошо читаемым: // в rxReport - уже лежит полученный пакет (USB hid) if (rxReport.command == Command.GetDeviceInfo) { txReport.deviceInfo.bootloaderVersion = settings.getBootloaderVersion(); txReport.deviceInfo.firmwareVersion = settings.getFirmwareVersion(); txReport.deviceInfo.hardwareVersion = settings.getHardwareVersion(); txReport.deviceInfo.serialNumber = settings.getSerialNumber(); ...... txReport.command = Command.Ok; sendReport(txReport); return; } if (rxReport.command == Command.GetFirmwareFitures) { txReport.firmwareFitures.baseAddr = FIRMWARE_BASE_ADDRESS; txReport.firmwareFitures.memorySize = FLASH_SIZE_KB * 1024UL; .... txReport.command = Command.Ok; sendReport(txReport); return; } if (rxReport.command == Command.DeviceReset) { txReport.command = Command.Ok; sendReport(txReport); NVIC_SystemReset(); } if (rxReport.command == Command.BootloaderActivate) { settings.killFirmware(); NVIC_SystemReset(); } if (rxReport.command == Command.SerialNumberChange) { settings.setSerialNumber(rxReport.deviceInfo.serialNumber); // Other "deviceInfo" fields are ignored txReport.command = Command.Ok; sendReport(txReport); return; } ..... Никаких адских массивов и массы магических чисел в качестве индесов для доступа к его содержимого. Через полгода/год открою этот код и сразу пойму, что тут происходит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба да оно и неявно сработает, и в этом случае без enum class "eMytype::max_enum_elents" будет лишнимНеявно сработает только в случае простого enum. В случае enum class нужно явное приведение и "eMytype::max_enum_elents" тоже будет нужно. Но как enum сделать гарантированно char ами?enum class eMytype : uint8_t {}. И еще: char, signed char и unsigned char - три разных типа, поэтому "голый" char нужно использовать только для хранения символов. Для чисел нужно использовать signed char и unsigned char, а еще лучше (u)uint8_t. Если бы у вас был enum eMytype { '1', '2', '3' } - вот тогда бы я к char не придирался. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка. Command - НЕ глобальная переменная, а статическая константа, которую, кстати, надо будет сделать constexpr.... Вообще, в данном примере показан бут-загручик (!) в одном из старых проектов, а эта структура Command используется прямо внутри соотв. cpp файла. Сам набор эти команд (Command) имеет смысл делать видимым только внутри этого модуля (в данном случае он называется Communication). Чтобы не загромождать соотв hpp файл никому не нужным снаружи этим набором команд, то они просто добавлены внутри соотв. cpp файла и им приписано static. По сути эта const struct - замена enum, видимая только внутри cpp файла, но позволяющая более легко читать текст, благодаря разбиения на поля и подструктуры. Впрочем, в данный момент, глядя на эти исходники, некоторые мелочи я бы сделал иначе. ... Но суть не в этом, а в том, что пример я привел для того, чтобы показать как можно обойтись без enion вообще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 13 августа, 2018 Опубликовано 13 августа, 2018 · Жалоба Неявно сработает только в случае простого enum. В случае enum class нужно явное приведение и "eMytype::max_enum_elents" тоже будет нужно. enum class eMytype : uint8_t {}. И еще: char, signed char и unsigned char - три разных типа, поэтому "голый" char нужно использовать только для хранения символов. Для чисел нужно использовать signed char и unsigned char, а еще лучше (u)uint8_t. Если бы у вас был enum eMytype { '1', '2', '3' } - вот тогда бы я к char не придирался. Какие придирки? Так я и спрашиваю, как сделать перечисление, где каждый элемент это char? Выше выяснили, что так вот просто через enum компиляторонезависимо не выйдет. Завтра поиграю с юнионом по совету. Command - НЕ глобальная переменная, а статическая константа, которую, кстати, надо будет сделать constexpr.... Вообще, в данном примере показан бут-загручик (!) в одном из старых проектов, а эта структура Command используется прямо внутри соотв. cpp файла. Сам набор эти команд (Command) имеет смысл делать видимым только внутри этого модуля (в данном случае он называется Communication). Чтобы не загромождать соотв hpp файл никому не нужным снаружи этим набором команд, то они просто добавлены внутри соотв. cpp файла и им приписано static. По сути эта const struct - замена enum, видимая только внутри cpp файла, но позволяющая более легко читать текст, благодаря разбиения на поля и подструктуры. Впрочем, в данный момент, глядя на эти исходники, некоторые мелочи я бы сделал иначе. ... Но суть не в этом, а в том, что пример я привел для того, чтобы показать как можно обойтись без enion вообще. Да не замена это. Энум нигде не хранится, просто объявление. Можно сделать его на пару миилиардов элементов, а при использовании поле его займет 4 байта. С const struct несколько не то. Надо ещё подумать Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться