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

(Я знаю, что все это делает помимо части ##.)

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

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

Он называется оператором вставки; он конкатенирует текст в 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 )->bit 0

Без этого вам придется определить bit часть макроса как один из аргументов макроса:

 #define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bt 

где использование будет:

 REGISTER_BIT(myreg, bit0) 

что является более громоздким.

Это также позволяет создавать новые имена.

Предположим, что у вас есть эти macros:

 #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 префиксом. Без hashей у вас будет 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);