У меня есть набор определенных макросов следующим образом.
#define ARM_FRONT_REG 1
..............
#define ARM_REAR_REG 10
#define MOTOR_MAIN_REG 1
..............
#define MOTOR_AUX_REG 3
#define MOTOR_REGISTER_ADDRESS(register_offset) \
( \
addr = MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset) \
) \
#define ARM_REGISTER_ADDRESS(register_offset) \
( \
addr = ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset) \
) \
Я использую макросы, такие как
ui_address = ARM_BASE_ADDR (ARM_REAR_REG)
ui_address = MOTOR_REGISTER_ADDRESS (MOTOR_MAIN_REG)
Я хочу ограничить использование макросов, которые смешиваются друг с другом. Есть ли способ прервать компиляцию, если макросы используются следующим образом?
ui_address = ARM_BASE_ADDR (MOTOR_MAIN_REG)
ui_address = MOTOR_REGISTER_ADDRESS (ARM_REAR_REG)
PS: Я кратко упомянул макросы, но фактические макросы, как показано ниже, используются для чтения регистров и записи в драйвер Linux из пользовательского приложения.
фактическая структура:
struct hw_register_struct
{
int log_level;
unsigned int reg_addr;
unsigned int reg_value;
char reg_name [MAX_REG_NAME_LENGTH];
char application_info [APP_INFO_LENGTH];
};
Этот макрос проверяет правильность адреса для каждого модуля.
#define CHECK_ADDR_SUB_MODULE(module_index, sub_module, sub_module_bits, offset, max_reg_count)
({
unsigned int check_ret = 0;
if (offset >= max_reg_count){
hw_register.reg_addr = 0;
check_ret = 1;
} else {
hw_register.reg_addr = (module_index * (1 << BITS_PER_MODULE) + (1 << sub_module_bits) * (sub_module) + offset);
}
check_ret;
})
Этот макрос присваивает адрес переменной в структуре.
#define SEQUENCER_REGISTER_ADDRESS(register_offset)
({
memset((void *)&hw_register, 0, sizeof(struct hw_register_struct));
if (CHECK_ADDR_SUB_MODULE(MODULE_SEQUENCER, 0, register_offset, SEQ_REG_COUNT)){
Logger::Print(ERROR_LEVEL, "Invalid Address | Module : %s | Address : %s", STR(MODULE_SEQUENCER), #register_offset);
}
memcpy(hw_register.reg_name, #register_offset, sizeof(#register_offset));
hw_register.reg_addr;
})
Выполнить вызов драйвера ioctl для Linux
#define WRITE_REGISTER_(register_addr, register_value, func, line, log_level_)
{
register_addr;
hw_register.reg_value = register_value;
hw_register.log_level = log_level_;
snprintf(hw_register.application_info, APP_INFO_LENGTH - 1,"%s:%d", func, line);
long ret_ioctl = p_IOCTL->IOCTL<struct hw_register_struct>(IOCTL_WRITE, hw_register);
if (unlikely(ret_ioctl != 0))
{
Logger::Print(ERROR_LEVEL, "IOCTL WRITE_REGISTER Failed | Reg: %u, Reg Name [ %s ]", hw_register.reg_addr, hw_register.reg_name);
}
}
#define WRITE_REGISTER_INFO(register_addr, register_value) WRITE_REGISTER_(register_addr, register_value, __func__, __LINE__, KERN_INFO_LEVEL)
@RobertHarvey, все определения макросов являются целыми числами.
Почему это макрос? I am using macros like
Почему вы ставите addr =
, а потом ставите ui_address =
? Зачем устанавливать эту addr =
, что во всем этом делает переменная addr
?
В вашем случае вы можете сделать так, чтобы макросы принимали аргументы, добавляя префикс имени к переданному аргументу. Например.:
#define ARM_REGISTER_ADDRESS(register_offset) \
( \
addr = ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + ARM_##register_offset) \
)
##
объединит ARM_ и аргумент, переданный макросу. Затем вы можете использовать его как:
ui_address = ARM_BASE_ADDR (REAR_REG);
И
ui_address = ARM_BASE_ADDR (MAIN_REG);
Не получится, потому что ARM_MAIN_REG не существует (в вашем случае).
Но я не думаю, что проверка типов даже с использованием перечислений решит вашу проблему (по крайней мере, я не знаю, чтобы компилятор разрешал это).
Кроме того, я только что понял, что addr =
, вероятно, не должен быть частью ваших макросов.
Если вам нужно сделать это в препроцессоре, вы можете использовать тег с переменными, а затем объединить его с уникальным именем, которое расширится до результата, что-то вроде:
#define MOTOR_BASE_ADDR 1
#define BITS_PER_MODULE 2
#define ARM_FRONT_REG (ARM, 1)
#define ARM_REAR_REG (ARM, 10)
#define MOTOR_MAIN_REG (MOTOR, 1)
#define MOTOR_AUX_REG (MOTOR, 3)
#define MOTOR_UNIQUE_STRING(x) x
#define MOTOR_ONLY(a, b) a##_UNIQUE_STRING(b)
#define MOTOR_REGISTER_ADDRESS(register_offset) \
( MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + MOTOR_ONLY register_offset )
#define ARM_UNIQUE_STRING_FDASDFSAFDA(x) x
#define ARM_ONLY(a, b) a##_UNIQUE_STRING_FDASDFSAFDA(b)
#define ARM_REGISTER_ADDRESS(register_offset) \
( ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + ARM_ONLY register_offset )
int main() {
MOTOR_REGISTER_ADDRESS(MOTOR_MAIN_REG); // all fine
MOTOR_REGISTER_ADDRESS(ARM_FRONT_REG); // error - sytnax error or ARM_UNIQUE_STRING undeclared
}
Выбор уникального имени тега и уникальной строки по существу будет работать как защита от странных имен. Вы можете выбрать более уникальное имя для функций.
Вы можете использовать фактические правильные типы и использовать фактическую функцию в зависимости от того, что один тип структуры не может быть преобразован в другой:
struct arm_register { long v; };
static const struct arm_register ARM_FRONT_REG = {1};
struct motor_register { long v; };
static const struct motor_register MOTOR_MAIN_REG = {1};
#define MOTOR_BASE_ADDR 1
#define BITS_PER_MODULE 2
static inline long MOTOR_REGISTER_ADDRESS(struct motor_register register_offset) {
return MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset.v;
}
int main() {
MOTOR_REGISTER_ADDRESS(MOTOR_MAIN_REG); // all fine
MOTOR_REGISTER_ADDRESS(ARM_FRONT_REG); // error - incompatible type
}
# or with _Generic:
#define MOTOR_REGISTER_ADDRESS_2(x) \
_Generic((x), struct motor_register: MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + x.v)
static const int a = MOTOR_REGISTER_ADDRESS_2(MOTOR_MAIN_REG); // all fine
static const int b = MOTOR_REGISTER_ADDRESS_2(ARM_FRONT_REG); // error - _Generic can't be chosen
Для этого вам понадобится информация о типе данных, не так ли? Все ваши определенные константы по существу являются целыми числами. так что их никак не отличить.