Перейти к содержанию
    

Поиск по массиву в compile time на С

Для доступа по индексу можно так сделать

enum VARIABLES { 
    VAR1, 
    VAR2, 
    ...
    VARN,
    VAR_MAX 
};

описание списка переменных

const TVAR VarArray[VAR_MAX] = {
    [VAR1] = <тут ваша реализация>,
    [VAR2] = <тут ваша реализация>,
    ...
    [VARN] = <тут ваша реализация>
};

собственно ваш реестр инициализации.

Обращение к реестру можно делать по индексу (0-N) или по имени (VAR1-VARN).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

Пытаясь понять этот трудночитаемый набор слов, мне удалось понять мысль - один компилятор трактует enum как char, а другой - как int.

Но это вроде как решаемо: всего лишь в enum нужно явно указать тип хранимых данных.

Примерно так: typedef enum { Eins, Zwei, Polizei, empty = (uint32_t)0xffffff }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А наоборот как ?

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++)

Только вот так не получится , да и понятно почему (второе изображение)

Выходит в С слишком опасно, в С++ слишком неудобно либо неэффективно. Решение есть, вот оно и ищется

post-5493-1534184097_thumb.png

post-5493-1534184509_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По-ходу я ошибся с явным указанием типа enum, у меня не работает :(

Нужно это делать ключами компилятора: http://www.keil.com/support/man/docs/armcl...11640303038.htm

 

Кстати, у меня pragma pack вот так используется:

#pragma pack(push, 1)
....
#pragma pack(pop)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

max_enum_elents будет строго типизировано и пробежаться по его его варинтам вплоть до него "по индексу" не выйдет.
Явное приведение типа все еще работает. for(uint_fast8_t i = 0;i < uint_fast8_t(eMytype::max_enum_elents); ++i)/

Симпатично, жаль это since C99
18 лет, уже не девочка...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Явное приведение типа все еще работает. 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 ами?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По-ходу я ошибся с явным указанием типа 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.. А вот тут споткнулся

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот тут споткнулся

В "протокольных" делах 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;
}

.....

Никаких адских массивов и массы магических чисел в качестве индесов для доступа к его содержимого.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным

static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

да оно и неявно сработает, и в этом случае без 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 не придирался.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гы, const struct а тут мы возвращаемся к вопросу их инициализации, который вы почему то сочли непонятным

static const struct это к кому относится? Разве что делать отдельный namespace как вариант ? Иначе также самая нелюбимая вами глобальная переменная. Глобальная в одном файле - все равно не отмазка.

Command - НЕ глобальная переменная, а статическая константа, которую, кстати, надо будет сделать constexpr....

Вообще, в данном примере показан бут-загручик (!) в одном из старых проектов, а эта структура Command используется прямо внутри соотв. cpp файла.

Сам набор эти команд (Command) имеет смысл делать видимым только внутри этого модуля (в данном случае он называется Communication).

Чтобы не загромождать соотв hpp файл никому не нужным снаружи этим набором команд, то они просто добавлены внутри соотв. cpp файла и им приписано static.

По сути эта const struct - замена enum, видимая только внутри cpp файла, но позволяющая более легко читать текст, благодаря разбиения на поля и подструктуры.

 

Впрочем, в данный момент, глядя на эти исходники, некоторые мелочи я бы сделал иначе. ...

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неявно сработает только в случае простого 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 несколько не то. Надо ещё подумать

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...