Оператор ## в 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.)

Ответ 1

Это конкатенация строк, как часть макроса препроцессора.

(В этом контексте "строка" относится к конечному маркеру препроцессора, или к "строке исходного кода", а не к строке C.)

Ответ 2

Он называется оператором вставки; он объединяет текст в bt с текстом bit. Так, например, если ваш вызов макроса был

REGISTER_BIT(x, 4)

Он будет расширяться до

((volatile _io_reg*)&x)->bit4

Без этого вы не могли бы поставить макрокоманд непосредственно рядом с текстом в макрообъекте, потому что тогда текст коснулся имени аргумента и стал частью того же токена, и он стал бы другим именем.

Ответ 3

Оператор ## объединяет два аргумента, не оставляя между ними пробелов:

#define glue(a,b) a ## b
glue(c,out) << "test";

Ответ 5

Эта часть определения макроса.

Он позволяет вам конкатенировать строки внутри макроса.

В вашем случае вы можете использовать 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)

Ответ 6

Это не конструкция C, это препроцессорная функция. В этом случае это означало оценить переменную bt и объединить ее с префиксом bit. Без хэшей у вас будет bitbt, что явно не сработает.

Ответ 7

Вот пример из 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);