Какова цель #define директивы в C++?

Какова роль #define директива?

6
задан Brian Tompsett - 汤莱恩 27 November 2015 в 15:46
поделиться

8 ответов

inCorrectUseOfHashDefine ()

{

Роль #define состоит в том, чтобы сбивать с толку людей, которые наследуют ваш код, неожиданными утверждениями вроде:

foreverandever

из-за:

#define foreverandever for(;;)

}

Пожалуйста, отдавайте предпочтение константам над #define.

Это также для установки директив компилятора ...

0
ответ дан 8 December 2019 в 04:28
поделиться

#define используется для создания макросов в C и в C++. Подробнее об этом можно прочитать в документации по препроцессору C. Быстрый ответ заключается в том, что он делает несколько вещей:

  1. Простые макросы - в основном просто замена текста. Хорошим примером являются константы времени компиляции:

    #define SOME_CONSTANT 12
    

    просто заменяет текст SOME_CONSTANT на 12 везде, где он появляется в вашем коде. Подобные макросы часто используются для условной компиляции блоков кода. Например, в каждом исходном файле проекта может быть заголовок, содержащий список опций проекта:

    #define OPTION_1
    #define OPTION_2
    #undef OPTION_3
    

    А затем блоки кода в проекте будут обернуты соответствующими блоками #ifdef/#endif# для включения и отключения этих опций в готовом проекте. Использование флага -D gcc обеспечит аналогичное поведение. Однако существуют различные мнения о том, является ли этот метод действительно хорошим способом обеспечения конфигурации приложения.

  2. Макросы с аргументами - позволяют создавать "функционально-подобные" макросы, которые могут принимать аргументы и манипулировать ими. Например:

    #define SQUARE(x) ((x) * (x))
    

    вернет квадрат аргумента в качестве результата; будьте осторожны с возможными проблемами порядка операций или побочных эффектов! Следующий пример:

    int x = SQUARE(3); // становится int x = ((3) * (3));
    

    будет работать нормально, но что-то вроде:

    int y = SQUARE(f()); // становится int y = ((f()) * (f()));
    

    вызовет f() дважды, или еще хуже:

    int z = SQUARE(x++); // становится int z = ((x++) * (x++));
    

    приводит к неопределенному поведению!

    С помощью некоторых инструментов макросы с аргументами также могут быть переменными, что может пригодиться.

Как упоминалось ниже в комментариях, чрезмерное использование макросов или создание слишком сложных или запутанных макросов многие считают плохим стилем - как всегда, ставьте читабельность, сопровождаемость и отлаживаемость вашего кода выше "умных" технических приемов.

14
ответ дан 8 December 2019 в 04:28
поделиться

#define (и его противоположность, #undef) можно использовать для установки директив компилятора, которые затем можно проверить с помощью #ifndef или #ifdef. Это позволяет определять пользовательское поведение в исходном файле. Обычно это используется для компиляции для различных окружений или отладки кода.

An example:

#define DEBUG



#ifdef DEBUG

//perform debug code

#endif
7
ответ дан 8 December 2019 в 04:28
поделиться

Наиболее распространенное использование (на далеко) #define - это включение защит:

// header.hh
#ifndef HEADER_HH_
#define HEADER_HH_

namespace pony {
// ...
}

#endif

Другое распространенное использование #define - это создание конфигурационного файла, обычно config.h, где мы #define макросы, основанные на различных состояниях и условиях. Затем в нашем коде мы проверяем эти макросы с помощью #ifdef, #elif defined() и т.д. для поддержки различных компиляций для различных ситуаций. Это не так надежно, как идиома include-guard, и здесь нужно быть осторожным, потому что если ветвление будет неправильным, вы можете получить очень непонятные ошибки компилятора или, что еще хуже, поведение во время выполнения.

В общем, за исключением include guard'ов, вам нужно обдумать проблему (желательно дважды) и посмотреть, можно ли использовать для ее решения компилятор, а не препроцессор. Компилятор просто умнее препроцессора. И не только это, но компилятор не может запутать препроцессор, в то время как препроцессор определенно может запутать и ввести в заблуждение компилятор.

2
ответ дан 8 December 2019 в 04:28
поделиться

Директива #define имеет два общих применения.

Первый - это управление действиями компилятора. Для этого нам также понадобятся #undef, #ifdef и #ifndef. (и #endif тоже ...)

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

#ifdef DEBUG

//debug code here

#endif

И вы могли бы, например, скомпилировать отладочный код, написав #define DEBUG

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

Пример, файл A, # включает файлы B и C. Но файл B также включает C. Это, вероятно, приведет к ошибке компиляции, поскольку "C" существует дважды.

Решение таково:

#ifndef C_FILE_INCLUDED
#define C_FILE_INCLUDED

//the contents of header "c" go here.

#endif

Другое использование #define - это макросы make.

Самые простые из них состоят из простых замен, например:

#define PI 3.14159265

float perimeter(float radius) {
    return radius*2*PI;
}

или

#define SHOW_ERROR_MESSAGE printf("An serious error happened");

if ( 1 != 1 ) { SHOW_ERROR_MESSAGE }

Затем вы также можете создавать макросы, принимающие аргументы, printf сам по себе обычно является макросом, созданным с помощью #define в файле заголовка.

Но этого не следует делать по двум причинам: во-первых, макросы скорости ОС такие же, как и при использовании встроенных, а во-вторых, у нас есть шаблоны C ++, которые позволяют больше контролировать функции с переменным типом. . Итак, единственная причина использовать макросы с аргументами - создавать странные конструкции, которые позже будет трудно понять, например, метапрограммированные вещи ...

1
ответ дан 8 December 2019 в 04:28
поделиться

в C или C++ #define позволяет создавать макросы препроцессора.

В обычном процессе сборки C или C++ первым делом запускается препроцессор, который просматривает исходные файлы на наличие директив препроцессора, таких как #define или #include, а затем выполняет с ними простые операции.

в случае директивы #define препроцессор выполняет простую текстовую подстановку.

Например, если у вас есть код

#define PI 3.14159f

float circum = diameter*PI;

препроцессор превратит его в:

float circum = diameter* 3.14159;

просто заменив экземпляры PI на соответствующий текст. Это лишь простейшая форма оператора #define, для более продвинутого использования ознакомьтесь с этой статьей из MSDN

.
0
ответ дан 8 December 2019 в 04:28
поделиться

О #defines уже много говорилось, но не ясно, есть ли в C++ лучшие замены для большинства их применений:

  1. #define для определения числовых констант можно легко заменить на const "переменную", которая, как #define, не существует в скомпилированном исполняемом файле. AFAIK она может быть использована почти во всех ситуациях, где вы могли бы использовать #defined числовую константу, включая границы массива. Основным преимуществом для меня является то, что такие константы четко типизированы, поэтому нет необходимости добавлять касты в макросы "на всякий случай", и скопированы, поэтому их можно хранить в пространствах имен/классах/функциях, не загрязняя все приложение.

const int max_array_size=50;
int an_array[max_array_size];
  1. #define для создания макросов: макросы часто можно заменить шаблонами; например, ужасный макрос MAX

#define MAX(a,b)    ((a)<(b)?(b):(a))

, который имеет несколько недостатков (например. повторная оценка аргументов, неизбежное расширение в линию), может быть заменен функцией max

template<typename T> T & max(T & a, T & b)
{
    return a<b?b:a;
}

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

Тем не менее, макросы все равно должны использоваться для включения защит, для создания каких-то странных расширений языка, которые расширяются на большее количество строк кода, имеют несбалансированные скобки и т.д.

0
ответ дан 8 December 2019 в 04:28
поделиться

В C ++ #define имеет очень узкие, специализированные роли:

  • Защита заголовков, описанная в других ответах
  • Взаимодействие со стандартными библиотеками. Например, #defining WINDOWS_LEAN_AND_MEAN перед включением windows.h отключает некоторые часто проблемные макросы, такие как MAX.
  • Расширенные макросы, включающие преобразование в строки (т. Е. Макросы, печатающие отладочные сообщения) или вставку токена.

Вам следует избегать использования #define для следующих целей. Причин много; см. для instace этот раздел часто задаваемых вопросов .

  • Константы времени компиляции. Вместо этого используйте const .
  • Простые функции макросов. Вместо этого используйте встроенные функции и шаблоны.
1
ответ дан 8 December 2019 в 04:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: