Ограничение аргумента макроса C префиксом аргумента

У меня есть набор определенных макросов следующим образом.

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

Для этого вам понадобится информация о типе данных, не так ли? Все ваши определенные константы по существу являются целыми числами. так что их никак не отличить.

Robert Harvey 10.12.2020 15:38

@RobertHarvey, все определения макросов являются целыми числами.

user3478108 10.12.2020 16:01

Почему это макрос? I am using macros like Почему вы ставите addr =, а потом ставите ui_address =? Зачем устанавливать эту addr =, что во всем этом делает переменная addr?

KamilCuk 10.12.2020 16:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В вашем случае вы можете сделать так, чтобы макросы принимали аргументы, добавляя префикс имени к переданному аргументу. Например.:

#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 =, вероятно, не должен быть частью ваших макросов.

Julien Thierry 10.12.2020 16:11

Если вам нужно сделать это в препроцессоре, вы можете использовать тег с переменными, а затем объединить его с уникальным именем, которое расширится до результата, что-то вроде:

#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

Другие вопросы по теме