inCorrectUseOfHashDefine ()
{
Роль #define состоит в том, чтобы сбивать с толку людей, которые наследуют ваш код, неожиданными утверждениями вроде:
foreverandever
из-за:
#define foreverandever for(;;)
}
Пожалуйста, отдавайте предпочтение константам над #define.
Это также для установки директив компилятора ...
#define
используется для создания макросов в C и в C++. Подробнее об этом можно прочитать в документации по препроцессору C. Быстрый ответ заключается в том, что он делает несколько вещей:
Простые макросы - в основном просто замена текста. Хорошим примером являются константы времени компиляции:
#define SOME_CONSTANT 12
просто заменяет текст SOME_CONSTANT
на 12
везде, где он появляется в вашем коде. Подобные макросы часто используются для условной компиляции блоков кода. Например, в каждом исходном файле проекта может быть заголовок, содержащий список опций проекта:
#define OPTION_1
#define OPTION_2
#undef OPTION_3
А затем блоки кода в проекте будут обернуты соответствующими блоками #ifdef
/#endif#
для включения и отключения этих опций в готовом проекте. Использование флага -D
gcc обеспечит аналогичное поведение. Однако существуют различные мнения о том, является ли этот метод действительно хорошим способом обеспечения конфигурации приложения.
Макросы с аргументами - позволяют создавать "функционально-подобные" макросы, которые могут принимать аргументы и манипулировать ими. Например:
#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++));
приводит к неопределенному поведению!
С помощью некоторых инструментов макросы с аргументами также могут быть переменными, что может пригодиться.
Как упоминалось ниже в комментариях, чрезмерное использование макросов или создание слишком сложных или запутанных макросов многие считают плохим стилем - как всегда, ставьте читабельность, сопровождаемость и отлаживаемость вашего кода выше "умных" технических приемов.
#define (и его противоположность, #undef) можно использовать для установки директив компилятора, которые затем можно проверить с помощью #ifndef или #ifdef. Это позволяет определять пользовательское поведение в исходном файле. Обычно это используется для компиляции для различных окружений или отладки кода.
An example:
#define DEBUG
#ifdef DEBUG
//perform debug code
#endif
Наиболее распространенное использование (на далеко) #define
- это включение защит:
// header.hh
#ifndef HEADER_HH_
#define HEADER_HH_
namespace pony {
// ...
}
#endif
Другое распространенное использование #define
- это создание конфигурационного файла, обычно config.h, где мы #define
макросы, основанные на различных состояниях и условиях. Затем в нашем коде мы проверяем эти макросы с помощью #ifdef
, #elif defined()
и т.д. для поддержки различных компиляций для различных ситуаций. Это не так надежно, как идиома include-guard, и здесь нужно быть осторожным, потому что если ветвление будет неправильным, вы можете получить очень непонятные ошибки компилятора или, что еще хуже, поведение во время выполнения.
В общем, за исключением include guard'ов, вам нужно обдумать проблему (желательно дважды) и посмотреть, можно ли использовать для ее решения компилятор, а не препроцессор. Компилятор просто умнее препроцессора. И не только это, но компилятор не может запутать препроцессор, в то время как препроцессор определенно может запутать и ввести в заблуждение компилятор.
Директива #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 ++, которые позволяют больше контролировать функции с переменным типом. . Итак, единственная причина использовать макросы с аргументами - создавать странные конструкции, которые позже будет трудно понять, например, метапрограммированные вещи ...
в C или C++ #define позволяет создавать макросы препроцессора.
В обычном процессе сборки C или C++ первым делом запускается препроцессор, который просматривает исходные файлы на наличие директив препроцессора, таких как #define или #include, а затем выполняет с ними простые операции.
в случае директивы #define препроцессор выполняет простую текстовую подстановку.
Например, если у вас есть код
#define PI 3.14159f
float circum = diameter*PI;
препроцессор превратит его в:
float circum = diameter* 3.14159;
просто заменив экземпляры PI на соответствующий текст. Это лишь простейшая форма оператора #define, для более продвинутого использования ознакомьтесь с этой статьей из MSDN
.О #defines уже много говорилось, но не ясно, есть ли в C++ лучшие замены для большинства их применений:
const int max_array_size=50;
int an_array[max_array_size];
#define MAX(a,b) ((a)<(b)?(b):(a))
, который имеет несколько недостатков (например. повторная оценка аргументов, неизбежное расширение в линию), может быть заменен функцией max
template<typename T> T & max(T & a, T & b)
{
return a<b?b:a;
}
, которая может быть безопасной с точки зрения типов (в этой версии два аргумента должны быть одного типа), может быть расширена в линию, а также нет (это решение компилятора), оценивает аргументы только один раз (когда вызывается), и является масштабируемой. Более подробное объяснение можно найти здесь.
Тем не менее, макросы все равно должны использоваться для включения защит, для создания каких-то странных расширений языка, которые расширяются на большее количество строк кода, имеют несбалансированные скобки и т.д.
В C ++ #define имеет очень узкие, специализированные роли:
Вам следует избегать использования #define для следующих целей. Причин много; см. для instace этот раздел часто задаваемых вопросов .
const
. встроенные
функции и шаблоны.