Операторы препроцессора # и ##

nullptr

Для чего они нужны и как их использовать ?

3 ответа

nullptr

# размещенный перед аргументом макроса превращает его в строку. Например код:

#define QUOTE(a) #a

int main() {
    cout << QUOTE(2 + 2) << " = " << 4 << endl;
}

после работы препроцессора превратится в

int main() {
    cout << "2 + 2" << " = " << 4 << endl;
}

Полезный пример использования - отладочный макрос ASSERT. Пример реализации:

#define ASSERT(c) \
    if (!c) { \
        std::cerr << "Assertion failed in " << __FILE__ \
                  << "(line " << __LINE__ << ") : " << #c << std::endl; \
        exit(1); \
    }

Если его передать ему ложное условие, например ASSERT(2 * 2 != 4), то он выведет нечто вроде:

Assertion failed in test.cpp(line 12) : 2 * 2 != 4

и завершит работу программы.

## нужен, чтобы склевать аргументы макроса с другими частями макроса или друг с другом. Применяется он редко, в основном для кодогенерации. Пример из википедии:

#define MYCASE(item,id) \
    case id: \
       item##_##id = id;\
    break

    switch(x) {
        MYCASE(widget,23);
     }

После препроцессинга превращается в:

switch (x) {
    case 23:
        widget_23 = 23;
    break;
}


nullptr

В начале строки # означает собственно начало директивы препроцессора. В середине директивы она вот что обозначает. Дело в том, что если макрос находится внутри кавычек, замены не происходит. Если же нам нужно заключить макрозамену в кавычки, можно написать:

#define macro(a)  puts(#a)

Строка

macro (text);

будет развернута так

puts ("text");

Два знака ## произведут при развертывании конкатенацию фактических параметров макроса:

#define macro(a, b)  a##b

macro (name, 1)

развернется в

name1

См. K&R гл. 4.11.2


nullptr

Примерно так.

Директивы препроцессора:

#define CONSTANT value //определение константы
#include file_name     //включение в проект файла file_name
#pragma  option        //задаем машинно-зависимые опции(опции компилятора)
#define CONSTANT(paaram1) definition   //определяем макрос
#ifdef CONSTANT        //включает дальнейший код, если константа ОПРЕДЕЛЕНА
#ifndef CONSTANT       //включает дальнейший кот только если константа НЕ определена
#else        //используется с двумя предыдущими. Включает или исключает дальнейший
//код в зависимости от выполнения условия пред. раздела
#endif //конец условно включаемых/исключаемых фрагментов кода

Примерно так...

UPD: Оператор ## используется очень нечасто, так что за него можно и не думать...

licensed under cc by-sa 3.0 with attribution.