Что означает эта линия? В частности, что означает ##
?
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
Edit:
Немного смущен. Каким будет результат без ##
?
Что означает эта линия? В частности, что означает ##
?
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
Edit:
Немного смущен. Каким будет результат без ##
?
Немного смущен. Каким будет результат без ##?
Обычно вы не заметите никакой разницы. Но есть разница. Предположим, что Something
имеет тип:
struct X { int x; };
X Something;
И посмотрите:
int X::*p = &X::x;
ANALYZE(x, flag)
ANALYZE(*p, flag)
Без оператора конкатенации токена ##
он расширяется до:
#define ANALYZE(variable, flag) ((Something.variable) & (flag))
((Something. x) & (flag))
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error!
С конкатенацией маркера он расширяется до:
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
((Something.x) & (flag))
((Something.*p) & (flag)) // .* is a newly generated token, now it works!
Важно помнить, что препроцессор работает с токенами препроцессора, не по тексту. Поэтому, если вы хотите объединить два токена, вы должны явно сказать это.
##
называется объединением токенов, используется для объединения двух токенов при вызове макроса.
Видеть это:
Одна очень важная часть состоит в том, что эта маркерная конкатенация следует некоторым очень специальным правилам:
например. IBM doc:
Примеры также очень понятны
#define ArgArg(x, y) x##y
#define ArgText(x) x##TEXT
#define TextArg(x) TEXT##x
#define TextText TEXT##text
#define Jitter 1
#define bug 2
#define Jitterbug 3
С выходом:
ArgArg(lady, bug) "ladybug"
ArgText(con) "conTEXT"
TextArg(book) "TEXTbook"
TextText "TEXTtext"
ArgArg(Jitter, bug) 3
Источник - это документация IBM. Может отличаться от других компиляторов.
К вашей строке:
Он объединяет атрибут переменной с "Кое-что". и адресует переменную, которая логически обоснована, что дает результат, если Something.variable имеет установленный флаг.
Итак, пример моего последнего комментария и вашего вопроса (скомпилированный с g++):
// this one fails with a compiler error
// #define ANALYZE1(variable, flag) ((Something.##variable) & (flag))
// this one will address Something.a (struct)
#define ANALYZE2(variable, flag) ((Something.variable) & (flag))
// this one will be Somethinga (global)
#define ANALYZE3(variable, flag) ((Something##variable) & (flag))
#include <iostream>
using namespace std;
struct something{
int a;
};
int Somethinga = 0;
int main()
{
something Something;
Something.a = 1;
if (ANALYZE2(a,1))
cout << "Something.a is 1" << endl;
if (!ANALYZE3(a,1))
cout << "Somethinga is 0" << endl;
return 1;
};
Согласно Википедии
Конкатенация токена, также называемая вставкой токенов, является одной из самых тонких и простых в использовании функций препроцессора макросов C. Два аргумента могут быть "склеены" вместе с использованием оператора ## preprocessor; это позволяет объединить два токена в предварительно обработанном коде. Это можно использовать для создания сложных макросов, которые действуют как грубая версия шаблонов С++.
Отметьте Конкатенация токена
Это не ответ на ваш вопрос, просто сообщение CW с некоторыми советами, которые помогут вам самостоятельно изучить препроцессор.
Шаг предварительной обработки фактически выполняется перед компиляцией любого реального кода. Другими словами, когда компилятор начинает создавать ваш код, никаких операторов #define и ничего подобного не остается.
Хороший способ понять, что делает препроцессор для вашего кода, - это получить предварительно обработанный вывод и посмотреть на него.
Вот как это сделать для Windows:
Создайте простой файл с именем test.cpp и поместите его в папку, например c:\temp. Мой выглядит так:
#define dog_suffix( variable_name ) variable_name##dog
int main()
{
int dog_suffix( my_int ) = 0;
char dog_suffix( my_char ) = 'a';
return 0;
}
Не очень полезно, но просто. Откройте командную строку Visual Studio, перейдите в папку и запустите следующую командную строку:
c:\temp>cl test.cpp /P
Итак, это компилятор вашего запуска (cl.exe) с вашим файлом и параметр /P указывает компилятору сохранить предварительно обработанный вывод в файл.
Теперь в папке рядом с test.cpp вы найдете test.i, который для меня выглядит следующим образом:
#line 1 "test.cpp"
int main()
{
int my_intdog = 0;
char my_chardog = 'a';
return 0;
}
Как вы видите, не осталось #define, а только код, в который он был добавлен.
рассмотрим другой пример:
рассмотрим
#define MYMACRO(x,y) x##y
без ##
, очевидно, что препроцессор не может видеть x
и y
в качестве отдельных токенов, не так ли?
В вашем примере
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
##
просто не требуется, поскольку вы не создаете новый идентификатор. На самом деле компилятор выпускает "error: inserting". "И" variable "не дает допустимого токена предварительной обработки"