реклама на сайте
подробности

 
 
5 страниц V  < 1 2 3 4 > »   
Reply to this topicStart new topic
> Поиск по массиву в compile time на С
Nixon
сообщение Aug 13 2018, 13:58
Сообщение #16


Гуру
******

Группа: Админы
Сообщений: 2 736
Регистрация: 17-06-04
Из: Киев
Пользователь №: 48



Для доступа по индексу можно так сделать
Код
enum VARIABLES {
    VAR1,
    VAR2,
    ...
    VARN,
    VAR_MAX
};
описание списка переменных
Код
const TVAR VarArray[VAR_MAX] = {
    [VAR1] = <тут ваша реализация>,
    [VAR2] = <тут ваша реализация>,
    ...
    [VARN] = <тут ваша реализация>
};
собственно ваш реестр инициализации.
Обращение к реестру можно делать по индексу (0-N) или по имени (VAR1-VARN).


--------------------
Вам помочь или не мешать?
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 14:51
Сообщение #17


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(Nixon @ Aug 13 2018, 16:58) *
Для доступа по индексу можно так сделать...

a14.gif


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 17:36
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



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

Цитата(Nixon @ Aug 13 2018, 16:58) *
Для доступа по индексу можно так сделать
Код
enum VARIABLES {
    VAR1,
    VAR2,
    ...
    VARN,
    VAR_MAX
};
описание списка переменных
Код
const TVAR VarArray[VAR_MAX] = {
    [VAR1] = <тут ваша реализация>,
    [VAR2] = <тут ваша реализация>,
    ...
    [VARN] = <тут ваша реализация>
};
собственно ваш реестр инициализации.
Обращение к реестру можно делать по индексу (0-N) или по имени (VAR1-VARN).

Симпатично, жаль это since C99, поэтому не так много где описано и использовано. Буду знать.
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 17:39
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(DASM @ Aug 13 2018, 20:11) *
...

Пытаясь понять этот трудночитаемый набор слов, мне удалось понять мысль - один компилятор трактует enum как char, а другой - как int.
Но это вроде как решаемо: всего лишь в enum нужно явно указать тип хранимых данных.
Примерно так: typedef enum { Eins, Zwei, Polizei, empty = (uint32_t)0xffffff }


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 18:15
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



А наоборот как ?
Код
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++)

Только вот так не получится , да и понятно почему (второе изображение)
Выходит в С слишком опасно, в С++ слишком неудобно либо неэффективно. Решение есть, вот оно и ищется
Эскизы прикрепленных изображений
Прикрепленное изображение
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 18:25
Сообщение #21


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



По-ходу я ошибся с явным указанием типа enum, у меня не работает sad.gif
Нужно это делать ключами компилятора: http://www.keil.com/support/man/docs/armcl...11640303038.htm

Кстати, у меня pragma pack вот так используется:
Код
#pragma pack(push, 1)
....
#pragma pack(pop)



--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 13 2018, 18:31
Сообщение #22


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (DASM @ Aug 13 2018, 20:36) *
max_enum_elents будет строго типизировано и пробежаться по его его варинтам вплоть до него "по индексу" не выйдет.
Явное приведение типа все еще работает. for(uint_fast8_t i = 0;i < uint_fast8_t(eMytype::max_enum_elents); ++i)/
QUOTE (DASM @ Aug 13 2018, 20:36) *
Симпатично, жаль это since C99
18 лет, уже не девочка...


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 18:37
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(Сергей Борщ @ Aug 13 2018, 21:31) *
Явное приведение типа все еще работает. 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 ами?
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 18:39
Сообщение #24


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(DASM @ Aug 13 2018, 21:37) *
Но как enum сделать гарантированно char ами?

Остается только ключами компилятора


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 18:43
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(Forger @ Aug 13 2018, 21:25) *
По-ходу я ошибся с явным указанием типа enum, у меня не работает sad.gif
Нужно это делать ключами компилятора: 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.. А вот тут споткнулся
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 19:28
Сообщение #26


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(DASM @ Aug 13 2018, 21:43) *
А вот тут споткнулся

В "протокольных" делах enum не использую, но очень активно использую union:

CODE
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 делает его очень компактным и также хорошо читаемым:

CODE

// в 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;
}

.....

Никаких адских массивов и массы магических чисел в качестве индесов для доступа к его содержимого.
Через полгода/год открою этот код и сразу пойму, что тут происходит.


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 19:39
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным
static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 13 2018, 19:47
Сообщение #28


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (DASM @ Aug 13 2018, 21:37) *
да оно и неявно сработает, и в этом случае без enum class "eMytype::max_enum_elents" будет лишним
Неявно сработает только в случае простого enum. В случае enum class нужно явное приведение и "eMytype::max_enum_elents" тоже будет нужно.
QUOTE (DASM @ Aug 13 2018, 21:37) *
Но как 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 не придирался.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Forger
сообщение Aug 13 2018, 19:49
Сообщение #29


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(DASM @ Aug 13 2018, 22:39) *
Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным
static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка.

Command - НЕ глобальная переменная, а статическая константа, которую, кстати, надо будет сделать constexpr....
Вообще, в данном примере показан бут-загручик (!) в одном из старых проектов, а эта структура Command используется прямо внутри соотв. cpp файла.
Сам набор эти команд (Command) имеет смысл делать видимым только внутри этого модуля (в данном случае он называется Communication).
Чтобы не загромождать соотв hpp файл никому не нужным снаружи этим набором команд, то они просто добавлены внутри соотв. cpp файла и им приписано static.
По сути эта const struct - замена enum, видимая только внутри cpp файла, но позволяющая более легко читать текст, благодаря разбиения на поля и подструктуры.

Впрочем, в данный момент, глядя на эти исходники, некоторые мелочи я бы сделал иначе. ...
Но суть не в этом, а в том, что пример я привел для того, чтобы показать как можно обойтись без enion вообще.


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
DASM
сообщение Aug 13 2018, 20:08
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(Сергей Борщ @ Aug 13 2018, 22:47) *
Неявно сработает только в случае простого 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 компиляторонезависимо не выйдет. Завтра поиграю с юнионом по совету.


Цитата(Forger @ Aug 13 2018, 22:49) *
Command - НЕ глобальная переменная, а статическая константа, которую, кстати, надо будет сделать constexpr....
Вообще, в данном примере показан бут-загручик (!) в одном из старых проектов, а эта структура Command используется прямо внутри соотв. cpp файла.
Сам набор эти команд (Command) имеет смысл делать видимым только внутри этого модуля (в данном случае он называется Communication).
Чтобы не загромождать соотв hpp файл никому не нужным снаружи этим набором команд, то они просто добавлены внутри соотв. cpp файла и им приписано static.
По сути эта const struct - замена enum, видимая только внутри cpp файла, но позволяющая более легко читать текст, благодаря разбиения на поля и подструктуры.

Впрочем, в данный момент, глядя на эти исходники, некоторые мелочи я бы сделал иначе. ...
Но суть не в этом, а в том, что пример я привел для того, чтобы показать как можно обойтись без enion вообще.

Да не замена это. Энум нигде не хранится, просто объявление. Можно сделать его на пару миилиардов элементов, а при использовании поле его займет 4 байта. С const struct несколько не то. Надо ещё подумать
Go to the top of the page
 
+Quote Post

5 страниц V  < 1 2 3 4 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th April 2024 - 03:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.01522 секунд с 7
ELECTRONIX ©2004-2016