Инициализация структуры с помощью unsigned short id
с помощью #define
...
static unsigned short mId = 0;
typedef struct
{
/* data */
unsigned short id;
const char *name;
bool enabled;
} Machine;
#define CREATE_MACHINE(_mName_) Machine m##_mName_ = {mId++, #_mName_, false};
Как я могу увеличить mId
для следующей инициализации экземпляра? mId++
не допускается в инициализаторе.
Итак, я также попробовал использовать функцию, как было предложено в одном комментарии:
static Machine _create_machine(const char *name)
{
unsigned short id = mId++;
Machine m = {id, name, false};
return m;
}
// corrected typo in method parameter
#define CREATE_MACHINE(_mName_) Machine m##_mName_ = _create_machine(#_mName_);
Невозможно использовать функцию в постоянном выражении.
Полный исходник по запросу...
// main.c
#include <stdio.h>
#include <stdbool.h>
#include "../include/machine.h"
MAKE_MACHINE(test)
int main()
{
PLACE(mtest);
printf("placed machine[%d] enabled: %s\n", mtest.id, B(mtest.enabled);
DROP(mtest);
printf("dropped machine[%d] enabled: %s\n", mtest.id, B(mtest.enabled);
}
// machine.h
#ifndef MACHINE_H
#define MACHINE_H
#include "op/data_types.h"
static USHORT mId = 0;
enum MachineState
{
M_IDLE,
M_RUN,
M_LOCK
};
typedef struct
{
/* data */
const USHORT id;
const CHAR *name;
BOOL enabled;
} Machine;
static Machine _make_machine(const char *name)
{
USHORT id = mId++;
Machine m = {id, name, false};
return m;
}
static void _place_machine(Machine *machine)
{
machine->enabled = true;
}
static void _drop_machine(Machine *machine)
{
machine->enabled = false;
}
#define MAKE_MACHINE(_mName_) Machine m##_mName_ = _make_machine(#_mName_);
#define PLACE(_machine_) _place_machine(&_machine_);
#define DROP(_machine_) _drop_machine(&_machine_);
#endif // MACHINE_H
Я попробовал использовать функцию, и ей тоже не понравилось использование функции, потому что это постоянное значение...??? Вот на что жаловалась IDE. Я добавлю это как то, что я пробовал.
Зачем пытаться сделать это с помощью макроса с динамически определяемым именем переменной, содержащим последовательные номера? Почему бы просто не сохранить их в массиве?
Вы пытаетесь использовать этот макрос для создания экземпляров области файлов? Это объясняет, почему mId++
вызывает у вас проблемы.
@user229044 user229044 Потому что в структуре есть id
, который необходимо назначать постепенно.
@dbush: да... в этом и цель. Я следую некоторым методам, с которыми недавно столкнулся, и изучаю ограничения, преимущества, плюсы и минусы. Но, по крайней мере, теперь я знаю, почему это не работает. Но хотелось бы найти решение (если оно есть).
Как вы компилируете версию функции? Для меня это компилируется чисто (gcc m.c -Wall -Wextra -o m
).
Функция будет работать. Полный рабочий пример:
#include <stdio.h>
#include <stdbool.h>
static unsigned short mId = 0;
typedef struct
{
/* data */
unsigned short id;
const char *name;
bool enabled;
} Machine;
static Machine make_machine(const char * name) {
// lock mutexes, atomic operations, etc.
unsigned short next_id = mId++;
// unlock mutexes if necessary
Machine ret = {next_id, name, false};
return ret;
}
#define CREATE_MACHINE(_mName_) Machine m##_mName_ = make_machine(#_mName_)
int main() {
CREATE_MACHINE(hello);
CREATE_MACHINE(world);
printf("%u: %s\n", mhello.id, mhello.name);
printf("%u: %s\n", mworld.id, mworld.name);
return 0;
}
Поскольку функция не ограничена таким же образом, мы можем выполнять дополнительную работу, например приращение mId
. Если вы хотите использовать разные увеличивающиеся переменные идентификатора, make_machine
может взять unsigned short*
, которым он манипулирует внутри самой функции, и который все равно может быть скрыт макросом.
Итак, вот как правильно инициализировать значение области файла. Если бы я действительно хотел создать эти константы, как бы я это сделал? Я неправильно понял, о чем говорилось в комментариях к сообщению относительно области действия файла.
Вы хотите, чтобы созданное Machine
было const
? Вам просто нужно добавить const
к типу в макросе (const Machine m##_mName_ = ...
).
ну, я думаю, я имел в виду глобальную область действия, а не файловую. IDE жаловалась, что функцию нельзя использовать в константном выражении, так что я думаю, это не const
. Все еще разбираюсь в понятиях. Хотя я понимаю. Цените помощь.
Если вы отредактируете свой вопрос, чтобы полностью показать свою первоначальную попытку и то, что не работает, я поиграю с этим и посмотрю, что смогу сделать. Ничего страшного, если он не скомпилируется, но это проще, чем гадать, как выглядит ваш код.
@StephenNewell Использование любого макроса в области файла не работает, поскольку инициализатор содержит выражение, которое не является постоянным выражением.
Я использую немного другой подход. Этот ответ наиболее полезен для понимания ограничений моего подхода.
Использование подобных макросов для сокрытия объявлений переменных обычно не лучшая идея, поскольку вы создаете некий «язык макросов», который сложно читать и поддерживать.
При этом вполне возможно сделать все это во время компиляции. Я бы внедрил шаблон проектирования «X-макросы» и поместил все имена в список:
#define MACHINE_NAMES(X) \
X(Bob) \
X(Bill) \
Затем мы можем сгенерировать перечисление на основе этого:
typedef enum
{
#define MACHINE_ENUM(name) MACHINE_##name,
MACHINE_NAMES(MACHINE_ENUM)
} machine_enum_t;
Все объявления переменных тогда станут:
#define CREATE_MACHINE(name) Machine m##name = {MACHINE_##name, #name, false};
MACHINE_NAMES(CREATE_MACHINE)
После предварительной обработки вы теперь сидите на чем-то вроде:
Machine mBob = {MACHINE_Bob, "Bob", false};
Machine mBill = {MACHINE_Bill, "Bill", false};
Где MACHINE_Bob
== 0, MACHINE_Bill
== 1 и так далее. Однако вам, вероятно, следует сделать это массивом - где MACHINE_##name
дает вам индекс массива.
Если я правильно понимаю этот подход, мне нужно знать все машины заранее. Это верно?
@IAbstract Да, это требование для всего, что разрешается во время компиляции.
Использовать функцию? В любом случае он вам понадобится, если вы собираетесь создать
Machine
в нескольких потоках одновременно.