2009-08-12 4 views
2

Прочитав еще один вопрос об использовании макросов, я задавался вопросом: что являются они хороши для?Что такое макросы препроцессора?

Одна вещь, которую я не вижу заменить на любой другой язык конструкции очень скоро в убывающей число родственных слов вам необходимо ввести следующее:

void log_type(const bool value) { std::cout << "bool: " << value; } 
void log_type(const int value) { std::cout << "int: " << value; } 
... 
void log_type(const char value) { std::cout << "char: " << value; } 
void log_type(const double value) { std::cout << "int: " << value; } 
void log_type(const float value) { std::cout << "float: " << value; } 

в отличие от

#define LOGFN(T) void log_type(const T value) { std::cout << #T ## ": " << value; } 
LOGFN(int) 
LOGFN(bool) 
... 
LOGFN(char) 
LOGFN(double) 
LOGFN(float) 

Любые другие «незаменимые»?

EDIT: пытается обобщить причины, по которым встречаются ответы; так как это меня заинтересовало. В основном потому, что у меня такое чувство, что большинство из них связано с тем, что мы все еще программируем в сырых текстовых файлах, но в то же время плохо поддерживающих средах.

  • гибкость кода в компилируется (например, проблемы #ifdef DEBUG платформы) (SadSido, Catalin, Гоз)
  • целей отладки (например, __LINE__, __TIME__); Я также поставил «подтягивание» по этой причине (SadSido, Jla3ep, Jason S)
  • заменить, например. РНР require против include функции (#pragma once) (SadSido, Каталин) повышение
  • читаемости путем замены сложного кода (например, MESSAGEMAP, BOOST_FOREACH) (SadSido, fnieto)
  • DRY принципа (Jason S)
  • сменных фильтрующей рядных (Маттиас Вандел, Роберт С.Barnes)
  • stringifying (Jason S)
+0

Первый вариант выглядит более понятным для меня. –

+0

Это точно. Это означает, что это плохой пример. Я постараюсь придумать лучшее. – xtofl

+0

Это не должно быть макросом, это должно быть просто функцией шаблона, например 'template void log_type (const T value) {...}'. Таким образом, использование макросов уже давно заменено другой языковой конструкцией. – sth

ответ

14
  • составить разный код при различных условиях (#ifdef __DEBUG__);
  • охранники для включения каждого заголовка один раз для каждой единицы перевода (#pragma once);
  • __FILE__ и __LINE__ - заменено на текущее имя файла и текущую строку;
  • структурирование кода, чтобы сделать его более читаемым (например: BEGIN_MESSAGE_MAP());

Смотреть интересное обсуждение макро на gotw здесь:

http://www.gotw.ca/gotw/032.htm

http://www.gotw.ca/gotw/077.htm

+2

BEGIN_MESSAGE_MAP просто скрывает ужас кодирования в реализации обработки сообщений Microsoft в MFC. –

+1

Точно. Это то, что я называю «сделать код более читаемым». Я использую «BEGIN_MESSAGE_MAP() ... END_MESSAGE_MAP()» вместо объявления некоторой огромной встроенной функции, состоящей из операторов switch. – SadSido

+1

+1: Построение статических таблиц - одно из мест, где макросам всегда трудно превзойти. Когда вы можете указать имя один раз, а затем использовать его несколько раз для разных вещей, это может фактически повысить надежность кода. Например, «#define BUILDROW (X) {#X, doGet ## X()}". Это именно то, что использует ???? _MESSAGE_MAP. –

7

Самый полезный - заголовок файла охранном:

#ifndef MY_HEADER_GUARD 
#define MY_HEADER_GUARD 

// Header file content. 

#endif 

Позже добавить [Windows, только]

Экспорт классов в DLL:

#ifdef EXPORT_MY_LIB 
#define MY_API __declspec(dllexport) 
#else 
#define MY_API __declspec(dllimport) 
#endif 

Класс образца:

class MY_API MyClass { ... }; 
+0

Экспорт поддерживается с помощью GCC. –

+0

Я имел в виду среду Windows, не обязательно для Visual C++. –

7

платформы конкретных разделов.

т.е.

#ifdef WINDOWS 
#include "WindowsImplementation.h" 
#elif defined(LINUX) 
#include "LinuxImplementation.h" 
#else 
#error Platform undefined. 
#endif 
+4

Я думаю, что это должно обрабатываться системой сборки, а не языком. – xtofl

+0

@xtofl Я никогда не видел, чтобы система сборки делала это, но это звучит интересно. У вас есть примеры этого в проекте C или C++? Спасибо – Glen

+0

Я думаю, что он имеет в виду что-то вроде функции Visual Studio «Исключить из сборки». Проблема, с которой я сталкиваюсь, заключается в том, что вы можете работать с несколькими разными компиляторами и т. Д. Я думаю, все это можно было бы сделать с помощью make-файла, но я работал над проектами, которые нужно было компилировать в GCC, Visual Studio и Code Warrior (например, PS2, X-Box и ПК и Wii). Его выполнение в этих условиях, но намного легче сделать вышеупомянутую ИМО. – Goz

4

Я отправил это раньше, но, конечно, не могу теперь найти его. Если вы хотите получить доступ к __FILE__ и __LINE__ макросов, то другой макрос, безусловно, является наиболее удобным способом пойти - например:

#define ATHROW(msg)           \ 
{               \ 
    std::ostringstream os;         \ 
    os << msg;            \ 
    throw ALib::Exception(os.str(), __LINE__, __FILE__); \ 
} 
+0

+1. Это единственное, с чем я согласен. –

+0

@ Jla3ep, даже не включать охранников? – AProgrammer

+0

'#pragma once' - это нестандартная, но широко поддерживаемая директива препроцессора, предназначенная для включения в исходный файл только один раз в одной компиляции. –

0

Современных языков принять философию, нуждающийся в proeprocessor INS знака отсутствующего языка , поэтому они определяют все виды языковых функций, которые препроцессор позаботился очень просто в старом стиле K & R. C.

Ваш пример кода, приведенный выше, может быть упрощен с помощью встроенной функции, например.

Лично, наиболее важным аспектом препроцессора является то, что ясно, что некоторые вещи выполняются скомпилировать время прямо в исходном коде. Java-подход для устранения путей мертвого кода во время компиляции не так очевиден при чтении кода.

+0

Я не думаю, что вы можете заменить его, не вводя каждое имя типа дважды. – xtofl

3

Для совершения крутых магических трюков, например, в BOOST_FOREACH, injecting variables в амбиции.

BOOST_FOREACH(char c, "Hello, world!") 
{ 
    ... use char variable c here ... 
} // c's scope ends here 
// if there's an outer c defined, its scope resumes here 
0

Одно из их применений в основном как функция плохих манов (встроенных).

For example:

#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y)) 

Это позволяет генерировать пользовательскую функцию MIN для любых типов, поддерживающих эти операторы, которые эффективно инлайн в точке Useage. Разумеется, проверки типов нет, и в конечном итоге легко получить странные синтаксические ошибки или неправильное поведение, если вы не получите парссов в порядке.

+2

Как вопрос о C++, зачем кому-то это делать, а не использовать шаблоны? – 2009-08-12 13:39:23

+0

Думаю, я просто думаю в C. Мне действительно хотелось бы увидеть функции шаблонов, перенесенные на C, чтобы избавиться от такого рода вещей. Я не предполагал, что вы знаете компилятор C, который поддерживает это? –

+3

X и Y могут быть функциями с большим количеством вычислений. При использовании макроса они будут вызываться дважды. При использовании функции шаблона они будут вызываться только один раз. –

3

Для причин, не связанных с повторением (DRY). Вещи, которые включают повторяющиеся конструкции во время компиляции, которые нельзя отвлечь в других методах (шаблоны или что у вас есть). Если вы обнаружите, что повторяете одни и те же конструкции кода 20 раз, это потенциальный источник человеческой ошибки, который, мы надеемся, можно отвлечь, используя шаблоны, но иногда нет. Это всегда баланс между преимуществами просмотра исходного кода, который может быть проверен и проверен явно, а также преимущества использования макросов для произвольных шаблонов замещения (которые обычно не могут быть проверены с помощью инструментов автоматического программирования).

Строка и конкатенация (шаблоны препроцессора # и ##) не могут быть выполнены с помощью шаблонов.

Конечно, в какой-то момент вам может быть полезно использовать инструмент (независимо от того, изготовлен ли он или готовый) для автоматического создания кода.

+0

+1 для обозначения принципа DRY _ в сочетании с отсутствием лучшего метода. – xtofl

+0

Вам понадобилось бы подравнивание и конкатенацию для целей, отличных от отладки? – xtofl

+0

+1 для упоминания о сокращении человеческой ошибки. Однажды я написал программу в javascript, которая написала ежемесячный отчет Microsoft Word. Взял 5 секунд, чтобы бежать, и никогда не было ошибок. До этого люди занимаются деньком (включая корректуру). Иногда даже после корректуры отчета, сгенерированного человеком, все еще были ошибки. – 2012-04-10 01:34:54

Смежные вопросы