Intereting Posts
Когда пространство стека выделяется для локальных переменных? Разница между массивами 1d и 2d в C вызов неуправляемой функции char возвращает char * Не являются ли значения ASCII от ‘a’ до ‘z’ последовательно от 97 до 122 независимо от реализации? В хорошей книге говорится об обратном Ошибка четного компилятора при использовании объектов Obj-C в операторе switch Самый быстрый способ скопировать несколько двумерных массивов в один одномерный массив (в C) Связывание со статической библиотекой Что такое «короткий» тип данных в C? Сигнал изменения текста GtkEntry Создайте против более новых заголовков Linux, чем libc, построенный с использованием Необработанное исключение для символа, обработанного из командной строки в API Win32 Realloc и sscanf в функцию преобразование строки в двойную переменную в C Как вы можете печатать несколько переменных внутри строки с помощью printf? В Linux, на C, как я могу получить все streamи процесса?

C Препроцессор генерирует macros путем конкатенации и строения

У меня есть набор целевых макросов, для которых я хочу генерировать псевдонимы на основе выбора макроса, например:

Выбор макроса:

#define I2C_MODULE 1 

Псевдоним макросов (концептуальная форма):

 #define I2C_MODULE_BASE I2C_BASE #define I2C_MODULE_NVIC INT_I2C 

Целевые macros (из внешнего файла из моего контроля):

 #define INT_I2C0 24 #define INT_I2C1 53 ... #define I2C0_BASE 0x40020000 #define I2C1_BASE 0x40021000 ... 

Я хотел, чтобы препроцессор генерировал macros псевдонимов I2C_MODULE_BASE и I2C_MODULE_NVIC на основе выбора макроса I2C_MODULE , но после многократного чтения Q1 , P1 и многих других ссылок, которые я потерял, я закончил жестко кодировать их значения. Ниже я покажу свои текущие рабочие определения, а затем мои последние неудачные попытки создания макросов:

Что работает:

 #define I2C_MODULE 1 #define I2C_MODULE_BASE I2C1_BASE #define I2C_MODULE_NVIC INT_I2C1 

что не получилось:

 #define I2C_MODULE 1 #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) /* Attempt 1 */ #define I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE" #define I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE) /* Attempt 2 */ #define _I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE" #define _I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE) #define I2C_MODULE_BASE _I2C_MODULE_BASE #define I2C_MODULE_NVIC _I2C_MODULE_NVIC 

EDIT: Я расширил принятый ответ, чтобы добраться туда, где я хотел, а именно:

 #define PASTE2(a, b) a ## b #define PASTE3(a, b, c) a ## b ## c #define _I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE) #define _I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x) #define I2C_MODULE_BASE _I2C_MODULE_BASE(I2C_MODULE) #define I2C_MODULE_NVIC _I2C_MODULE_NVIC(I2C_MODULE) 

    Это похоже на работу:

     #define I2C_MODULE 1 //Alias macros (conceptual form): //#define I2C_MODULE_BASE I2C_BASE //#define I2C_MODULE_NVIC INT_I2C //Target macros (from an external file out of my control): #define INT_I2C0 24 #define INT_I2C1 53 #define I2C0_BASE 0x40020000 #define I2C1_BASE 0x40021000 #define PASTE2(a, b) a ## b #define PASTE3(a, b, c) a ## b ## c #define I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE) #define I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x) extern int i2c_module_base = I2C_MODULE_BASE(I2C_MODULE); extern int i2c_module_nvic = I2C_MODULE_NVIC(I2C_MODULE); extern int i2c_module_base_0 = I2C_MODULE_BASE(0); extern int i2c_module_nvic_0 = I2C_MODULE_NVIC(0); extern int i2c_module_base_1 = I2C_MODULE_BASE(1); extern int i2c_module_nvic_1 = I2C_MODULE_NVIC(1); 

    Пример вывода (из cpp ):

     # 1 "xx.c" # 1 "" # 1 "" # 1 "xx.c" # 21 "xx.c" extern int i2c_module_base = 0x40021000; extern int i2c_module_nvic = 53; extern int i2c_module_base_0 = 0x40020000; extern int i2c_module_nvic_0 = 24; extern int i2c_module_base_1 = 0x40021000; extern int i2c_module_nvic_1 = 53; 

    Он тесно связан с моим ответом на препроцессор C и конкатенацию токенов .

    Несомненно, существуют и другие способы, I2C_MODULE_BASE могут быть написаны macros I2C_MODULE_BASE и I2C_MODULE_NVIC , но ключевыми I2C_MODULE_NVIC являются:

    1. Использование оператора торможения ## token (не оператор # stringifying).
    2. Использование двух уровней макроса (например, I2C_MODULE_BASE и PASTE3 ).

    Я подозреваю, что вы пишете драйвер I2C, который может в целом обрабатывать несколько периферийных устройств I2C на одном микроcontrollerе, не переписывая один и тот же код несколько раз.

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

     #define I2C1 ((volatile uint8_t*)0x12345678) // address of first hw register for I2C1 #define I2C2 ((volatile uint8_t*)0x55555555) // address of first hw register for I2C2 /* map all registers used for I2C, they will have same register layout for every peripheral no matter which one: */ #define I2C_CONTROL(base) (*(base + 0)) #define I2C_DATA(base) (*(base + 1)) ... // create some dummy typedef to make your functions look nice: typedef volatile uint8_t* I2C_t; // define whatever functions you need in the driver: void i2c_init (IC2_t bus); void i2c_send (I2C_t bus, const uint8_t* data, size_t n); ... // implement functions in a bus-independent way: void i2c_init (IC2_t bus) { I2C_CONTROL(bus) = THIS | THAT; // setup registers } // caller code: i2c_init(I2C1); i2c_init(I2C2); ... i2c_send(I2C1, "hello", 5); i2c_send(I2C2, "world", 5); 

    Просто используйте #if / #else / #endif

     #if (I2C_MODULE == 0) #define I2C_MODULE_BASE I2C0_BASE #define I2C_MODULE_NVIC INT_I2C0 #elif (I2C_MODULE == 1) #define I2C_MODULE_BASE I2C1_BASE #define I2C_MODULE_NVIC INT_I2C1 #else #error Unknown configuration #endif