Ответ 1
Это конкатенация строк, как часть макроса препроцессора.
(В этом контексте "строка" относится к конечному маркеру препроцессора, или к "строке исходного кода", а не к строке C.)
Что делает ##
в C?
Пример:
typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
(Я знаю, что все это делает, кроме ## part.)
Это конкатенация строк, как часть макроса препроцессора.
(В этом контексте "строка" относится к конечному маркеру препроцессора, или к "строке исходного кода", а не к строке C.)
Он называется оператором вставки; он объединяет текст в bt
с текстом bit
. Так, например, если ваш вызов макроса был
REGISTER_BIT(x, 4)
Он будет расширяться до
((volatile _io_reg*)&x)->bit4
Без этого вы не могли бы поставить макрокоманд непосредственно рядом с текстом в макрообъекте, потому что тогда текст коснулся имени аргумента и стал частью того же токена, и он стал бы другим именем.
Оператор ## объединяет два аргумента, не оставляя между ними пробелов:
#define glue(a,b) a ## b
glue(c,out) << "test";
Это токеновый оператор.
Эта часть определения макроса.
Он позволяет вам конкатенировать строки внутри макроса.
В вашем случае вы можете использовать bt
от 7 до 0, как это:
REGISTER_BIT(myreg, 0)
и он будет расширен следующим образом:
((volatile _io_reg*)&myreg)->bit0
Без этого вам нужно определить часть bit
макроса как один из аргументов макроса:
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bt
где использование будет:
REGISTER_BIT(myreg, bit0)
что является более громоздким.
Это также позволяет создавать новые имена.
Предположим, что у вас есть эти макросы:
#define AAA_POS 1
#define AAA_MASK (1 << AAA_POS)
#define BBB_POS 2
#define BBB_MASK (1 << BBB_POS)
и вам нужен макрос, который извлекает AAA из битового вектора. Вы можете написать это следующим образом:
#define EXTRACT(bv, field) ((bv & field##_MASK) >> field##_POS)
а затем вы используете его следующим образом:
EXTRACT(my_bitvector, AAA)
Это не конструкция C, это препроцессорная функция. В этом случае это означало оценить переменную bt
и объединить ее с префиксом bit
. Без хэшей у вас будет bitbt
, что явно не сработает.
Вот пример из ffmpeg
, макроса, который регистрирует как аудио, так и видео фильтры:
#define REGISTER_FILTER(X, x, y) \
{ \
extern AVFilter ff_##y##_##x; \
if (CONFIG_##X##_FILTER) \
avfilter_register(&ff_##y##_##x); \
}
и использование может быть:
REGISTER_FILTER(AECHO,aecho,af);
REGISTER_FILTER(VFLIP,vflip,vf);